@percepta/kaizen 0.9.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dashboard/pages/api/langfuse-action.js +9 -2
- package/dist/dashboard/pages/api/langfuse-action.js.map +1 -1
- package/dist/dashboard/pages/api/langfuse-dataset-item.js +5 -2
- package/dist/dashboard/pages/api/langfuse-dataset-item.js.map +1 -1
- package/dist/dashboard/pages/api/langfuse-dataset-mutation.js +1 -1
- package/dist/dashboard/pages/api/langfuse-dataset-mutation.js.map +1 -1
- package/dist/dashboard/pages/api/langfuse-dataset.js.map +1 -1
- package/dist/dashboard/pages/api/langfuse-datasets.js.map +1 -1
- package/dist/dashboard/pages/api/langfuse-trace-memberships.js +1 -1
- package/dist/dashboard/pages/api/langfuse-trace-memberships.js.map +1 -1
- package/dist/dashboard/pages/api/langfuse-trace.js.map +1 -1
- package/dist/dashboard/pages/api/langfuse-traces.js.map +1 -1
- package/dist/dashboard/pages/api/linear-ideas.js.map +1 -1
- package/dist/dashboard/pages/api/run-events.js.map +1 -1
- package/dist/dashboard/pages/api/run-failures.js.map +1 -1
- package/dist/dashboard/pages/api/run-traces.js.map +1 -1
- package/dist/dashboard/pages/api/runs.js.map +1 -1
- package/dist/dashboard/pages/api/systems.js +1 -1
- package/dist/dashboard/pages/api/systems.js.map +1 -1
- package/dist/dashboard/pages/api/trace-renderer-version.js +10 -3
- package/dist/dashboard/pages/api/trace-renderer-version.js.map +1 -1
- package/dist/dashboard/pages/api/trace-renderer.js +12 -26
- package/dist/dashboard/pages/api/trace-renderer.js.map +1 -1
- package/dist/dashboard/src/lib/bundle-custom-renderer.js +167 -0
- package/dist/dashboard/src/lib/bundle-custom-renderer.js.map +1 -0
- package/dist/dashboard/src/lib/custom-renderer-files.js.map +1 -1
- package/dist/dashboard/src/lib/custom-renderer-metadata.js.map +1 -1
- package/dist/dashboard/src/lib/custom-view-paths.js.map +1 -1
- package/dist/dashboard/src/lib/dataset-item-labeling.js +20 -0
- package/dist/dashboard/src/lib/dataset-item-labeling.js.map +1 -0
- package/dist/dashboard/src/lib/env.js.map +1 -1
- package/dist/dashboard/src/lib/langfuse-cache.js.map +1 -1
- package/dist/dashboard/src/lib/langfuse-creds.js.map +1 -1
- package/dist/dashboard/src/lib/langfuse-demo.js.map +1 -1
- package/dist/dashboard/src/lib/langfuse-errors.js.map +1 -1
- package/dist/dashboard/src/lib/langfuse-helpers.js.map +1 -1
- package/dist/dashboard/src/lib/run-api.js.map +1 -1
- package/dist/dashboard/src/lib/run-store.js.map +1 -1
- package/dist/dashboard/src/lib/types.js.map +1 -1
- package/dist/dashboard/src/lib/workspace-env.js.map +1 -1
- package/dist/dashboard/src/lib/workspace.js.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/langfuse.d.ts.map +1 -1
- package/dist/langfuse.js.map +1 -1
- package/dist/package.js +2 -2
- package/dist/shared/env-file.js.map +1 -1
- package/dist/shared/linear-ideas.js.map +1 -1
- package/dist/shared/linear-issue.js.map +1 -1
- package/dist/shared/view-types.d.ts.map +1 -1
- package/dist/shared/workspace-paths.js.map +1 -1
- package/dist/src/commands/create-view.js.map +1 -1
- package/dist/src/commands/guide.js.map +1 -1
- package/dist/src/commands/ideas.js.map +1 -1
- package/dist/src/commands/init-system.js.map +1 -1
- package/dist/src/commands/init.js.map +1 -1
- package/dist/src/commands/log.js.map +1 -1
- package/dist/src/commands/rebuild.js.map +1 -1
- package/dist/src/commands/run.js.map +1 -1
- package/dist/src/commands/studio.js.map +1 -1
- package/dist/src/lib/bootstrap.js.map +1 -1
- package/dist/src/lib/cli.js.map +1 -1
- package/dist/src/lib/events.js +2 -0
- package/dist/src/lib/events.js.map +1 -1
- package/dist/src/lib/fs-utils.js.map +1 -1
- package/dist/src/lib/leaderboard.js.map +1 -1
- package/dist/src/lib/parse-args.js.map +1 -1
- package/dist/src/lib/paths.js.map +1 -1
- package/dist/src/lib/promotion.js.map +1 -1
- package/dist/src/lib/prompt.js.map +1 -1
- package/dist/src/lib/run-dir.js.map +1 -1
- package/dist/src/lib/runner.js.map +1 -1
- package/dist/src/lib/system.js.map +1 -1
- package/dist/studio/client/assets/index-Dc4zGLjQ.css +1 -0
- package/dist/studio/client/assets/index-ElL5OoiH.js +9 -0
- package/dist/studio/client/index.html +2 -2
- package/dist/studio/server.d.ts.map +1 -1
- package/dist/studio/server.js.map +1 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +3 -3
- package/dist/studio/client/assets/index-Bwj0gucs.css +0 -1
- package/dist/studio/client/assets/index-DKAiSaYs.js +0 -9
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fs-utils.js","names":[],"sources":["../../../src/lib/fs-utils.ts"],"sourcesContent":["import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\n\nexport function ensureDir(p: string): void {\n mkdirSync(p, { recursive: true });\n}\n\nexport function writeFileSafely(\n p: string,\n contents: string,\n opts: { overwrite?: boolean } = {},\n): boolean {\n if (existsSync(p) && !opts.overwrite) return false;\n ensureDir(dirname(p));\n writeFileSync(p, contents);\n return true;\n}\n\nexport function applyVars(text: string, vars: Record<string, string>): string {\n return text.replace(/\\{\\{\\s*(\\w+)\\s*\\}\\}/g, (m, key) =>\n key in vars ? vars[key] : m,\n );\n}\n\nexport function appendIfMissing(path: string, line: string): boolean {\n const existing = existsSync(path) ? readFileSync(path, \"utf-8\") : \"\";\n if (existing.split(\"\\n\").some((l) => l.trim() === line.trim())) return false;\n ensureDir(dirname(path));\n const sep = existing.length === 0 || existing.endsWith(\"\\n\") ? \"\" : \"\\n\";\n writeFileSync(path, existing + sep + line + \"\\n\");\n return true;\n}\n"],"mappings":";;;AAGA,SAAgB,UAAU,GAAiB;
|
|
1
|
+
{"version":3,"file":"fs-utils.js","names":[],"sources":["../../../src/lib/fs-utils.ts"],"sourcesContent":["import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\n\nexport function ensureDir(p: string): void {\n mkdirSync(p, { recursive: true });\n}\n\nexport function writeFileSafely(\n p: string,\n contents: string,\n opts: { overwrite?: boolean } = {},\n): boolean {\n if (existsSync(p) && !opts.overwrite) return false;\n ensureDir(dirname(p));\n writeFileSync(p, contents);\n return true;\n}\n\nexport function applyVars(text: string, vars: Record<string, string>): string {\n return text.replace(/\\{\\{\\s*(\\w+)\\s*\\}\\}/g, (m, key) =>\n key in vars ? vars[key] : m,\n );\n}\n\nexport function appendIfMissing(path: string, line: string): boolean {\n const existing = existsSync(path) ? readFileSync(path, \"utf-8\") : \"\";\n if (existing.split(\"\\n\").some((l) => l.trim() === line.trim())) return false;\n ensureDir(dirname(path));\n const sep = existing.length === 0 || existing.endsWith(\"\\n\") ? \"\" : \"\\n\";\n writeFileSync(path, existing + sep + line + \"\\n\");\n return true;\n}\n"],"mappings":";;;AAGA,SAAgB,UAAU,GAAiB;CACzC,UAAU,GAAG,EAAE,WAAW,KAAK,CAAC;AAClC;AAEA,SAAgB,gBACd,GACA,UACA,OAAgC,CAAC,GACxB;CACT,IAAI,WAAW,CAAC,KAAK,CAAC,KAAK,WAAW,OAAO;CAC7C,UAAU,QAAQ,CAAC,CAAC;CACpB,cAAc,GAAG,QAAQ;CACzB,OAAO;AACT;AAEA,SAAgB,UAAU,MAAc,MAAsC;CAC5E,OAAO,KAAK,QAAQ,yBAAyB,GAAG,QAC9C,OAAO,OAAO,KAAK,OAAO,CAC5B;AACF;AAEA,SAAgB,gBAAgB,MAAc,MAAuB;CACnE,MAAM,WAAW,WAAW,IAAI,IAAI,aAAa,MAAM,OAAO,IAAI;CAClE,IAAI,SAAS,MAAM,IAAI,EAAE,MAAM,MAAM,EAAE,KAAK,MAAM,KAAK,KAAK,CAAC,GAAG,OAAO;CACvE,UAAU,QAAQ,IAAI,CAAC;CAEvB,cAAc,MAAM,YADR,SAAS,WAAW,KAAK,SAAS,SAAS,IAAI,IAAI,KAAK,QAC/B,OAAO,IAAI;CAChD,OAAO;AACT"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"leaderboard.js","names":[],"sources":["../../../src/lib/leaderboard.ts"],"sourcesContent":["import { existsSync, readdirSync, statSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { systemRunsDir, readJsonIfExists } from \"./run-dir.js\";\n\nexport interface RunSummary {\n run_id: string;\n system: string;\n variant: string;\n parent_id: string | null;\n hypothesis: string;\n status: \"complete\" | \"crashed\" | \"aborted\" | \"running\";\n score: number | null;\n n: number | null;\n promoted: boolean | null;\n started_at: string;\n ended_at: string | null;\n eval_version: number;\n dataset_version: string;\n events_path: string;\n state_path: string;\n manifest_path: string;\n linear_issue_id?: string | null;\n linear_issue_url?: string | null;\n}\n\nexport interface ManifestFile {\n run_id: string;\n system: string;\n variant: string;\n parent_id: string | null;\n hypothesis: string;\n git_sha?: string | null;\n git_branch?: string | null;\n worktree_root?: string | null;\n git_common_dir?: string | null;\n eval_version: number;\n dataset_version: string;\n started_at: string;\n host?: string;\n kaizen_version?: string;\n state_dir?: string;\n diagnostic?: boolean;\n linear_issue_id?: string | null;\n linear_issue_url?: string | null;\n}\n\nexport interface StateFile {\n run_id: string;\n status: RunSummary[\"status\"];\n score: number | null;\n n_total?: number | null;\n n_done?: number;\n promoted?: boolean | null;\n ended_at?: string | null;\n}\n\nexport function listRuns(stateDir: string, systemId: string): RunSummary[] {\n const dir = systemRunsDir(stateDir, systemId);\n if (!existsSync(dir)) return [];\n const out: RunSummary[] = [];\n for (const entry of readdirSync(dir)) {\n const runDir = join(dir, entry);\n if (!statSync(runDir).isDirectory()) continue;\n const manifest_path = join(runDir, \"manifest.json\");\n const state_path = join(runDir, \"state.json\");\n const events_path = join(runDir, \"events.jsonl\");\n const manifest = readJsonIfExists<ManifestFile>(manifest_path);\n if (!manifest) continue;\n const state = readJsonIfExists<StateFile>(state_path);\n out.push({\n run_id: manifest.run_id,\n system: manifest.system,\n variant: manifest.variant,\n parent_id: manifest.parent_id,\n hypothesis: manifest.hypothesis,\n status: state?.status ?? \"running\",\n score: state?.score ?? null,\n n: state?.n_total ?? null,\n promoted: state?.promoted ?? null,\n started_at: manifest.started_at,\n ended_at: state?.ended_at ?? null,\n eval_version: manifest.eval_version,\n dataset_version: manifest.dataset_version,\n events_path,\n state_path,\n manifest_path,\n linear_issue_id: manifest.linear_issue_id ?? null,\n linear_issue_url: manifest.linear_issue_url ?? null,\n });\n }\n // Newest first\n out.sort((a, b) => (b.started_at < a.started_at ? -1 : 1));\n return out;\n}\n\n/**\n * Promoted baseline = the most recent run that was promoted, under matching versions.\n * Falls back to the highest-scored complete run if nothing has been promoted yet\n * (e.g. the very first run before promotion semantics kick in).\n */\nexport function currentBaseline(\n runs: RunSummary[],\n evalVersion: number,\n datasetVersion: string,\n): RunSummary | null {\n const eligible = runs.filter(\n (r) =>\n r.status === \"complete\" &&\n r.score !== null &&\n r.eval_version === evalVersion &&\n r.dataset_version === datasetVersion,\n );\n if (eligible.length === 0) return null;\n // listRuns sorts newest-first; find the newest with promoted: true.\n const promoted = eligible.find((r) => r.promoted === true);\n if (promoted) return promoted;\n // Fallback: highest-scored eligible run when promotion data is unavailable.\n let best = eligible[0];\n for (const r of eligible) {\n if (r.score! > best.score!) best = r;\n }\n return best;\n}\n"],"mappings":";;;;AAwDA,SAAgB,SAAS,UAAkB,UAAgC;CACzE,MAAM,MAAM,cAAc,UAAU,
|
|
1
|
+
{"version":3,"file":"leaderboard.js","names":[],"sources":["../../../src/lib/leaderboard.ts"],"sourcesContent":["import { existsSync, readdirSync, statSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { systemRunsDir, readJsonIfExists } from \"./run-dir.js\";\n\nexport interface RunSummary {\n run_id: string;\n system: string;\n variant: string;\n parent_id: string | null;\n hypothesis: string;\n status: \"complete\" | \"crashed\" | \"aborted\" | \"running\";\n score: number | null;\n n: number | null;\n promoted: boolean | null;\n started_at: string;\n ended_at: string | null;\n eval_version: number;\n dataset_version: string;\n events_path: string;\n state_path: string;\n manifest_path: string;\n linear_issue_id?: string | null;\n linear_issue_url?: string | null;\n}\n\nexport interface ManifestFile {\n run_id: string;\n system: string;\n variant: string;\n parent_id: string | null;\n hypothesis: string;\n git_sha?: string | null;\n git_branch?: string | null;\n worktree_root?: string | null;\n git_common_dir?: string | null;\n eval_version: number;\n dataset_version: string;\n started_at: string;\n host?: string;\n kaizen_version?: string;\n state_dir?: string;\n diagnostic?: boolean;\n linear_issue_id?: string | null;\n linear_issue_url?: string | null;\n}\n\nexport interface StateFile {\n run_id: string;\n status: RunSummary[\"status\"];\n score: number | null;\n n_total?: number | null;\n n_done?: number;\n promoted?: boolean | null;\n ended_at?: string | null;\n}\n\nexport function listRuns(stateDir: string, systemId: string): RunSummary[] {\n const dir = systemRunsDir(stateDir, systemId);\n if (!existsSync(dir)) return [];\n const out: RunSummary[] = [];\n for (const entry of readdirSync(dir)) {\n const runDir = join(dir, entry);\n if (!statSync(runDir).isDirectory()) continue;\n const manifest_path = join(runDir, \"manifest.json\");\n const state_path = join(runDir, \"state.json\");\n const events_path = join(runDir, \"events.jsonl\");\n const manifest = readJsonIfExists<ManifestFile>(manifest_path);\n if (!manifest) continue;\n const state = readJsonIfExists<StateFile>(state_path);\n out.push({\n run_id: manifest.run_id,\n system: manifest.system,\n variant: manifest.variant,\n parent_id: manifest.parent_id,\n hypothesis: manifest.hypothesis,\n status: state?.status ?? \"running\",\n score: state?.score ?? null,\n n: state?.n_total ?? null,\n promoted: state?.promoted ?? null,\n started_at: manifest.started_at,\n ended_at: state?.ended_at ?? null,\n eval_version: manifest.eval_version,\n dataset_version: manifest.dataset_version,\n events_path,\n state_path,\n manifest_path,\n linear_issue_id: manifest.linear_issue_id ?? null,\n linear_issue_url: manifest.linear_issue_url ?? null,\n });\n }\n // Newest first\n out.sort((a, b) => (b.started_at < a.started_at ? -1 : 1));\n return out;\n}\n\n/**\n * Promoted baseline = the most recent run that was promoted, under matching versions.\n * Falls back to the highest-scored complete run if nothing has been promoted yet\n * (e.g. the very first run before promotion semantics kick in).\n */\nexport function currentBaseline(\n runs: RunSummary[],\n evalVersion: number,\n datasetVersion: string,\n): RunSummary | null {\n const eligible = runs.filter(\n (r) =>\n r.status === \"complete\" &&\n r.score !== null &&\n r.eval_version === evalVersion &&\n r.dataset_version === datasetVersion,\n );\n if (eligible.length === 0) return null;\n // listRuns sorts newest-first; find the newest with promoted: true.\n const promoted = eligible.find((r) => r.promoted === true);\n if (promoted) return promoted;\n // Fallback: highest-scored eligible run when promotion data is unavailable.\n let best = eligible[0];\n for (const r of eligible) {\n if (r.score! > best.score!) best = r;\n }\n return best;\n}\n"],"mappings":";;;;AAwDA,SAAgB,SAAS,UAAkB,UAAgC;CACzE,MAAM,MAAM,cAAc,UAAU,QAAQ;CAC5C,IAAI,CAAC,WAAW,GAAG,GAAG,OAAO,CAAC;CAC9B,MAAM,MAAoB,CAAC;CAC3B,KAAK,MAAM,SAAS,YAAY,GAAG,GAAG;EACpC,MAAM,SAAS,KAAK,KAAK,KAAK;EAC9B,IAAI,CAAC,SAAS,MAAM,EAAE,YAAY,GAAG;EACrC,MAAM,gBAAgB,KAAK,QAAQ,eAAe;EAClD,MAAM,aAAa,KAAK,QAAQ,YAAY;EAC5C,MAAM,cAAc,KAAK,QAAQ,cAAc;EAC/C,MAAM,WAAW,iBAA+B,aAAa;EAC7D,IAAI,CAAC,UAAU;EACf,MAAM,QAAQ,iBAA4B,UAAU;EACpD,IAAI,KAAK;GACP,QAAQ,SAAS;GACjB,QAAQ,SAAS;GACjB,SAAS,SAAS;GAClB,WAAW,SAAS;GACpB,YAAY,SAAS;GACrB,QAAQ,OAAO,UAAU;GACzB,OAAO,OAAO,SAAS;GACvB,GAAG,OAAO,WAAW;GACrB,UAAU,OAAO,YAAY;GAC7B,YAAY,SAAS;GACrB,UAAU,OAAO,YAAY;GAC7B,cAAc,SAAS;GACvB,iBAAiB,SAAS;GAC1B;GACA;GACA;GACA,iBAAiB,SAAS,mBAAmB;GAC7C,kBAAkB,SAAS,oBAAoB;EACjD,CAAC;CACH;CAEA,IAAI,MAAM,GAAG,MAAO,EAAE,aAAa,EAAE,aAAa,KAAK,CAAE;CACzD,OAAO;AACT;;;;;;AAOA,SAAgB,gBACd,MACA,aACA,gBACmB;CACnB,MAAM,WAAW,KAAK,QACnB,MACC,EAAE,WAAW,cACb,EAAE,UAAU,QACZ,EAAE,iBAAiB,eACnB,EAAE,oBAAoB,cAC1B;CACA,IAAI,SAAS,WAAW,GAAG,OAAO;CAElC,MAAM,WAAW,SAAS,MAAM,MAAM,EAAE,aAAa,IAAI;CACzD,IAAI,UAAU,OAAO;CAErB,IAAI,OAAO,SAAS;CACpB,KAAK,MAAM,KAAK,UACd,IAAI,EAAE,QAAS,KAAK,OAAQ,OAAO;CAErC,OAAO;AACT"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parse-args.js","names":[],"sources":["../../../src/lib/parse-args.ts"],"sourcesContent":["export type Flags = Record<string, string | boolean>;\n\nexport function parseFlags(argv: string[]): {\n positional: string[];\n flags: Flags;\n} {\n const positional: string[] = [];\n const flags: Flags = {};\n for (let i = 0; i < argv.length; i++) {\n const a = argv[i];\n if (a.startsWith(\"--\")) {\n const eq = a.indexOf(\"=\");\n let key: string, valFromEq: string | undefined;\n if (eq >= 0) {\n key = a.slice(2, eq);\n valFromEq = a.slice(eq + 1);\n } else {\n key = a.slice(2);\n }\n if (valFromEq !== undefined) {\n flags[key] = valFromEq;\n continue;\n }\n const next = argv[i + 1];\n // A flag's value is the next token unless it looks like another flag (starts with `-`).\n if (next === undefined || next.startsWith(\"-\")) {\n flags[key] = true;\n } else {\n flags[key] = next;\n i++;\n }\n } else if (a.startsWith(\"-\") && a.length > 1) {\n // Short flag like `-n 3`. Treat similarly to long flags.\n const key = a.slice(1);\n const next = argv[i + 1];\n if (next === undefined || next.startsWith(\"-\")) {\n flags[key] = true;\n } else {\n flags[key] = next;\n i++;\n }\n } else {\n positional.push(a);\n }\n }\n return { positional, flags };\n}\n\nexport function strFlag(flags: Flags, key: string): string | undefined {\n const v = flags[key];\n return typeof v === \"string\" ? v : undefined;\n}\n\nexport function boolFlag(flags: Flags, key: string): boolean {\n return flags[key] === true || flags[key] === \"true\";\n}\n"],"mappings":";AAEA,SAAgB,WAAW,MAGzB;CACA,MAAM,aAAuB,
|
|
1
|
+
{"version":3,"file":"parse-args.js","names":[],"sources":["../../../src/lib/parse-args.ts"],"sourcesContent":["export type Flags = Record<string, string | boolean>;\n\nexport function parseFlags(argv: string[]): {\n positional: string[];\n flags: Flags;\n} {\n const positional: string[] = [];\n const flags: Flags = {};\n for (let i = 0; i < argv.length; i++) {\n const a = argv[i];\n if (a.startsWith(\"--\")) {\n const eq = a.indexOf(\"=\");\n let key: string, valFromEq: string | undefined;\n if (eq >= 0) {\n key = a.slice(2, eq);\n valFromEq = a.slice(eq + 1);\n } else {\n key = a.slice(2);\n }\n if (valFromEq !== undefined) {\n flags[key] = valFromEq;\n continue;\n }\n const next = argv[i + 1];\n // A flag's value is the next token unless it looks like another flag (starts with `-`).\n if (next === undefined || next.startsWith(\"-\")) {\n flags[key] = true;\n } else {\n flags[key] = next;\n i++;\n }\n } else if (a.startsWith(\"-\") && a.length > 1) {\n // Short flag like `-n 3`. Treat similarly to long flags.\n const key = a.slice(1);\n const next = argv[i + 1];\n if (next === undefined || next.startsWith(\"-\")) {\n flags[key] = true;\n } else {\n flags[key] = next;\n i++;\n }\n } else {\n positional.push(a);\n }\n }\n return { positional, flags };\n}\n\nexport function strFlag(flags: Flags, key: string): string | undefined {\n const v = flags[key];\n return typeof v === \"string\" ? v : undefined;\n}\n\nexport function boolFlag(flags: Flags, key: string): boolean {\n return flags[key] === true || flags[key] === \"true\";\n}\n"],"mappings":";AAEA,SAAgB,WAAW,MAGzB;CACA,MAAM,aAAuB,CAAC;CAC9B,MAAM,QAAe,CAAC;CACtB,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;EACpC,MAAM,IAAI,KAAK;EACf,IAAI,EAAE,WAAW,IAAI,GAAG;GACtB,MAAM,KAAK,EAAE,QAAQ,GAAG;GACxB,IAAI,KAAa;GACjB,IAAI,MAAM,GAAG;IACX,MAAM,EAAE,MAAM,GAAG,EAAE;IACnB,YAAY,EAAE,MAAM,KAAK,CAAC;GAC5B,OACE,MAAM,EAAE,MAAM,CAAC;GAEjB,IAAI,cAAc,KAAA,GAAW;IAC3B,MAAM,OAAO;IACb;GACF;GACA,MAAM,OAAO,KAAK,IAAI;GAEtB,IAAI,SAAS,KAAA,KAAa,KAAK,WAAW,GAAG,GAC3C,MAAM,OAAO;QACR;IACL,MAAM,OAAO;IACb;GACF;EACF,OAAO,IAAI,EAAE,WAAW,GAAG,KAAK,EAAE,SAAS,GAAG;GAE5C,MAAM,MAAM,EAAE,MAAM,CAAC;GACrB,MAAM,OAAO,KAAK,IAAI;GACtB,IAAI,SAAS,KAAA,KAAa,KAAK,WAAW,GAAG,GAC3C,MAAM,OAAO;QACR;IACL,MAAM,OAAO;IACb;GACF;EACF,OACE,WAAW,KAAK,CAAC;CAErB;CACA,OAAO;EAAE;EAAY;CAAM;AAC7B;AAEA,SAAgB,QAAQ,OAAc,KAAiC;CACrE,MAAM,IAAI,MAAM;CAChB,OAAO,OAAO,MAAM,WAAW,IAAI,KAAA;AACrC;AAEA,SAAgB,SAAS,OAAc,KAAsB;CAC3D,OAAO,MAAM,SAAS,QAAQ,MAAM,SAAS;AAC/C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"paths.js","names":[],"sources":["../../../src/lib/paths.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport {\n defaultKaizenStateDir,\n kaizenConfigPath,\n kaizenDir,\n kaizenSystemDir,\n kaizenSystemPath,\n kaizenSystemsDir,\n primaryWorktreeRoot,\n resolveKaizenStateDir,\n} from \"../../shared/workspace-paths.js\";\n\nconst HERE = dirname(fileURLToPath(import.meta.url));\n\nexport function packageRoot(): string {\n let dir = HERE;\n while (dir !== dirname(dir)) {\n if (existsSync(join(dir, \"package.json\"))) return dir;\n dir = dirname(dir);\n }\n return resolve(HERE, \"..\", \"..\");\n}\n\nexport function templatesDir(): string {\n return resolve(packageRoot(), \"templates\");\n}\n\nexport function workspaceRoot(): string {\n const raw = process.env.KAIZEN_WORKSPACE;\n return raw ? resolve(raw) : process.cwd();\n}\n\nexport {\n defaultKaizenStateDir,\n kaizenConfigPath,\n kaizenDir,\n kaizenSystemDir,\n kaizenSystemPath,\n kaizenSystemsDir,\n primaryWorktreeRoot,\n};\n\nexport function resolveStateDir(workspace: string): string {\n return resolveKaizenStateDir(workspace);\n}\n"],"mappings":";;;;;AAcA,MAAM,OAAO,QAAQ,cAAc,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"paths.js","names":[],"sources":["../../../src/lib/paths.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport {\n defaultKaizenStateDir,\n kaizenConfigPath,\n kaizenDir,\n kaizenSystemDir,\n kaizenSystemPath,\n kaizenSystemsDir,\n primaryWorktreeRoot,\n resolveKaizenStateDir,\n} from \"../../shared/workspace-paths.js\";\n\nconst HERE = dirname(fileURLToPath(import.meta.url));\n\nexport function packageRoot(): string {\n let dir = HERE;\n while (dir !== dirname(dir)) {\n if (existsSync(join(dir, \"package.json\"))) return dir;\n dir = dirname(dir);\n }\n return resolve(HERE, \"..\", \"..\");\n}\n\nexport function templatesDir(): string {\n return resolve(packageRoot(), \"templates\");\n}\n\nexport function workspaceRoot(): string {\n const raw = process.env.KAIZEN_WORKSPACE;\n return raw ? resolve(raw) : process.cwd();\n}\n\nexport {\n defaultKaizenStateDir,\n kaizenConfigPath,\n kaizenDir,\n kaizenSystemDir,\n kaizenSystemPath,\n kaizenSystemsDir,\n primaryWorktreeRoot,\n};\n\nexport function resolveStateDir(workspace: string): string {\n return resolveKaizenStateDir(workspace);\n}\n"],"mappings":";;;;;AAcA,MAAM,OAAO,QAAQ,cAAc,OAAO,KAAK,GAAG,CAAC;AAEnD,SAAgB,cAAsB;CACpC,IAAI,MAAM;CACV,OAAO,QAAQ,QAAQ,GAAG,GAAG;EAC3B,IAAI,WAAW,KAAK,KAAK,cAAc,CAAC,GAAG,OAAO;EAClD,MAAM,QAAQ,GAAG;CACnB;CACA,OAAO,QAAQ,MAAM,MAAM,IAAI;AACjC;AAEA,SAAgB,eAAuB;CACrC,OAAO,QAAQ,YAAY,GAAG,WAAW;AAC3C;AAEA,SAAgB,gBAAwB;CACtC,MAAM,MAAM,QAAQ,IAAI;CACxB,OAAO,MAAM,QAAQ,GAAG,IAAI,QAAQ,IAAI;AAC1C;AAYA,SAAgB,gBAAgB,WAA2B;CACzD,OAAO,sBAAsB,SAAS;AACxC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"promotion.js","names":[],"sources":["../../../src/lib/promotion.ts"],"sourcesContent":["import { bootstrapMeanCI, pairDeltas } from \"./bootstrap.js\";\nimport type { Event, ItemEvent, PromotionEvent } from \"./events.js\";\nimport { readNdjson } from \"./run-dir.js\";\n\nexport interface BaselineSummary {\n run_id: string;\n variant: string;\n score: number;\n events_path: string; // path to events.jsonl, used to lazily read item scores\n}\n\nexport type PromotionDecision = Omit<PromotionEvent, \"type\" | \"ts\">;\n\n/** Read item scores from a run's events.jsonl. Returns Map<item_id, score>. */\nfunction readItemScores(eventsPath: string): Map<string, number> {\n const events = readNdjson<Event>(eventsPath);\n const scores = new Map<string, number>();\n for (const e of events) {\n if (e.type === \"item\") {\n const it = e;\n scores.set(it.id, it.score);\n }\n }\n return scores;\n}\n\nexport interface DecideOpts {\n /** Set of subgroup keys to guard against regressions. */\n subgroupKeys?: string[];\n /** Bootstrap resamples; default 10k. */\n resamples?: number;\n /** Seed for determinism. */\n seed?: number;\n}\n\n/**\n * Decide auto-promotion given the current run's item scores and an optional baseline.\n * Returns a structured decision suitable for emitting as a `promotion` event.\n */\nexport function decidePromotion(\n currentScores: Map<string, number>,\n currentItemEvents: ItemEvent[],\n baseline: BaselineSummary | null,\n opts: DecideOpts = {},\n): PromotionDecision {\n if (!baseline) {\n return {\n promoted: true,\n rule: \"no_baseline\",\n n_compared: 0,\n details: \"no prior baseline; this run becomes the baseline by default\",\n };\n }\n\n const baselineScores = readItemScores(baseline.events_path);\n const { deltas, matchedIds } = pairDeltas(currentScores, baselineScores);\n if (deltas.length < 5) {\n return {\n promoted: false,\n rule: \"stat_insufficient\",\n n_compared: deltas.length,\n parent_run_id: baseline.run_id,\n details: `only ${deltas.length} items paired with baseline ${baseline.run_id}; need ≥5 to bootstrap`,\n };\n }\n\n const ci = bootstrapMeanCI(deltas, {\n resamples: opts.resamples,\n seed: opts.seed,\n });\n if (!(ci.ci_low > 0)) {\n return {\n promoted: false,\n rule: \"stat_insufficient\",\n ci_low: ci.ci_low,\n ci_high: ci.ci_high,\n mean_delta: ci.mean_delta,\n n_compared: ci.n,\n parent_run_id: baseline.run_id,\n details: `95% CI on mean delta is [${ci.ci_low.toFixed(4)}, ${ci.ci_high.toFixed(4)}]; lower bound is not > 0`,\n };\n }\n\n // Headline gate passed. Now check subgroup guards.\n if (opts.subgroupKeys && opts.subgroupKeys.length > 0) {\n const subgroupOf = (id: string, key: string): string | undefined => {\n for (const ev of currentItemEvents) {\n if (ev.id === id && ev.subgroup) return ev.subgroup[key];\n }\n return undefined;\n };\n for (const key of opts.subgroupKeys) {\n const groups = new Map<string, number[]>();\n for (let i = 0; i < matchedIds.length; i++) {\n const sg = subgroupOf(matchedIds[i], key);\n if (sg === undefined) continue;\n if (!groups.has(sg)) groups.set(sg, []);\n groups.get(sg)!.push(deltas[i]);\n }\n for (const [sg, sgDeltas] of groups) {\n if (sgDeltas.length < 5) continue; // not enough to test; ignore\n const sgCi = bootstrapMeanCI(sgDeltas, {\n resamples: opts.resamples,\n seed: opts.seed,\n });\n if (sgCi.ci_high < 0) {\n return {\n promoted: false,\n rule: \"subgroup_regression\",\n ci_low: ci.ci_low,\n ci_high: ci.ci_high,\n mean_delta: ci.mean_delta,\n n_compared: ci.n,\n parent_run_id: baseline.run_id,\n details: `subgroup ${key}=${sg} regressed: 95% CI [${sgCi.ci_low.toFixed(4)}, ${sgCi.ci_high.toFixed(4)}]`,\n };\n }\n }\n }\n }\n\n return {\n promoted: true,\n rule: \"auto\",\n ci_low: ci.ci_low,\n ci_high: ci.ci_high,\n mean_delta: ci.mean_delta,\n n_compared: ci.n,\n parent_run_id: baseline.run_id,\n };\n}\n"],"mappings":";;;;AAcA,SAAS,eAAe,YAAyC;CAC/D,MAAM,SAAS,WAAkB,
|
|
1
|
+
{"version":3,"file":"promotion.js","names":[],"sources":["../../../src/lib/promotion.ts"],"sourcesContent":["import { bootstrapMeanCI, pairDeltas } from \"./bootstrap.js\";\nimport type { Event, ItemEvent, PromotionEvent } from \"./events.js\";\nimport { readNdjson } from \"./run-dir.js\";\n\nexport interface BaselineSummary {\n run_id: string;\n variant: string;\n score: number;\n events_path: string; // path to events.jsonl, used to lazily read item scores\n}\n\nexport type PromotionDecision = Omit<PromotionEvent, \"type\" | \"ts\">;\n\n/** Read item scores from a run's events.jsonl. Returns Map<item_id, score>. */\nfunction readItemScores(eventsPath: string): Map<string, number> {\n const events = readNdjson<Event>(eventsPath);\n const scores = new Map<string, number>();\n for (const e of events) {\n if (e.type === \"item\") {\n const it = e;\n scores.set(it.id, it.score);\n }\n }\n return scores;\n}\n\nexport interface DecideOpts {\n /** Set of subgroup keys to guard against regressions. */\n subgroupKeys?: string[];\n /** Bootstrap resamples; default 10k. */\n resamples?: number;\n /** Seed for determinism. */\n seed?: number;\n}\n\n/**\n * Decide auto-promotion given the current run's item scores and an optional baseline.\n * Returns a structured decision suitable for emitting as a `promotion` event.\n */\nexport function decidePromotion(\n currentScores: Map<string, number>,\n currentItemEvents: ItemEvent[],\n baseline: BaselineSummary | null,\n opts: DecideOpts = {},\n): PromotionDecision {\n if (!baseline) {\n return {\n promoted: true,\n rule: \"no_baseline\",\n n_compared: 0,\n details: \"no prior baseline; this run becomes the baseline by default\",\n };\n }\n\n const baselineScores = readItemScores(baseline.events_path);\n const { deltas, matchedIds } = pairDeltas(currentScores, baselineScores);\n if (deltas.length < 5) {\n return {\n promoted: false,\n rule: \"stat_insufficient\",\n n_compared: deltas.length,\n parent_run_id: baseline.run_id,\n details: `only ${deltas.length} items paired with baseline ${baseline.run_id}; need ≥5 to bootstrap`,\n };\n }\n\n const ci = bootstrapMeanCI(deltas, {\n resamples: opts.resamples,\n seed: opts.seed,\n });\n if (!(ci.ci_low > 0)) {\n return {\n promoted: false,\n rule: \"stat_insufficient\",\n ci_low: ci.ci_low,\n ci_high: ci.ci_high,\n mean_delta: ci.mean_delta,\n n_compared: ci.n,\n parent_run_id: baseline.run_id,\n details: `95% CI on mean delta is [${ci.ci_low.toFixed(4)}, ${ci.ci_high.toFixed(4)}]; lower bound is not > 0`,\n };\n }\n\n // Headline gate passed. Now check subgroup guards.\n if (opts.subgroupKeys && opts.subgroupKeys.length > 0) {\n const subgroupOf = (id: string, key: string): string | undefined => {\n for (const ev of currentItemEvents) {\n if (ev.id === id && ev.subgroup) return ev.subgroup[key];\n }\n return undefined;\n };\n for (const key of opts.subgroupKeys) {\n const groups = new Map<string, number[]>();\n for (let i = 0; i < matchedIds.length; i++) {\n const sg = subgroupOf(matchedIds[i], key);\n if (sg === undefined) continue;\n if (!groups.has(sg)) groups.set(sg, []);\n groups.get(sg)!.push(deltas[i]);\n }\n for (const [sg, sgDeltas] of groups) {\n if (sgDeltas.length < 5) continue; // not enough to test; ignore\n const sgCi = bootstrapMeanCI(sgDeltas, {\n resamples: opts.resamples,\n seed: opts.seed,\n });\n if (sgCi.ci_high < 0) {\n return {\n promoted: false,\n rule: \"subgroup_regression\",\n ci_low: ci.ci_low,\n ci_high: ci.ci_high,\n mean_delta: ci.mean_delta,\n n_compared: ci.n,\n parent_run_id: baseline.run_id,\n details: `subgroup ${key}=${sg} regressed: 95% CI [${sgCi.ci_low.toFixed(4)}, ${sgCi.ci_high.toFixed(4)}]`,\n };\n }\n }\n }\n }\n\n return {\n promoted: true,\n rule: \"auto\",\n ci_low: ci.ci_low,\n ci_high: ci.ci_high,\n mean_delta: ci.mean_delta,\n n_compared: ci.n,\n parent_run_id: baseline.run_id,\n };\n}\n"],"mappings":";;;;AAcA,SAAS,eAAe,YAAyC;CAC/D,MAAM,SAAS,WAAkB,UAAU;CAC3C,MAAM,yBAAS,IAAI,IAAoB;CACvC,KAAK,MAAM,KAAK,QACd,IAAI,EAAE,SAAS,QAAQ;EACrB,MAAM,KAAK;EACX,OAAO,IAAI,GAAG,IAAI,GAAG,KAAK;CAC5B;CAEF,OAAO;AACT;;;;;AAeA,SAAgB,gBACd,eACA,mBACA,UACA,OAAmB,CAAC,GACD;CACnB,IAAI,CAAC,UACH,OAAO;EACL,UAAU;EACV,MAAM;EACN,YAAY;EACZ,SAAS;CACX;CAIF,MAAM,EAAE,QAAQ,eAAe,WAAW,eADnB,eAAe,SAAS,WACuB,CAAC;CACvE,IAAI,OAAO,SAAS,GAClB,OAAO;EACL,UAAU;EACV,MAAM;EACN,YAAY,OAAO;EACnB,eAAe,SAAS;EACxB,SAAS,QAAQ,OAAO,OAAO,8BAA8B,SAAS,OAAO;CAC/E;CAGF,MAAM,KAAK,gBAAgB,QAAQ;EACjC,WAAW,KAAK;EAChB,MAAM,KAAK;CACb,CAAC;CACD,IAAI,EAAE,GAAG,SAAS,IAChB,OAAO;EACL,UAAU;EACV,MAAM;EACN,QAAQ,GAAG;EACX,SAAS,GAAG;EACZ,YAAY,GAAG;EACf,YAAY,GAAG;EACf,eAAe,SAAS;EACxB,SAAS,4BAA4B,GAAG,OAAO,QAAQ,CAAC,EAAE,IAAI,GAAG,QAAQ,QAAQ,CAAC,EAAE;CACtF;CAIF,IAAI,KAAK,gBAAgB,KAAK,aAAa,SAAS,GAAG;EACrD,MAAM,cAAc,IAAY,QAAoC;GAClE,KAAK,MAAM,MAAM,mBACf,IAAI,GAAG,OAAO,MAAM,GAAG,UAAU,OAAO,GAAG,SAAS;EAGxD;EACA,KAAK,MAAM,OAAO,KAAK,cAAc;GACnC,MAAM,yBAAS,IAAI,IAAsB;GACzC,KAAK,IAAI,IAAI,GAAG,IAAI,WAAW,QAAQ,KAAK;IAC1C,MAAM,KAAK,WAAW,WAAW,IAAI,GAAG;IACxC,IAAI,OAAO,KAAA,GAAW;IACtB,IAAI,CAAC,OAAO,IAAI,EAAE,GAAG,OAAO,IAAI,IAAI,CAAC,CAAC;IACtC,OAAO,IAAI,EAAE,EAAG,KAAK,OAAO,EAAE;GAChC;GACA,KAAK,MAAM,CAAC,IAAI,aAAa,QAAQ;IACnC,IAAI,SAAS,SAAS,GAAG;IACzB,MAAM,OAAO,gBAAgB,UAAU;KACrC,WAAW,KAAK;KAChB,MAAM,KAAK;IACb,CAAC;IACD,IAAI,KAAK,UAAU,GACjB,OAAO;KACL,UAAU;KACV,MAAM;KACN,QAAQ,GAAG;KACX,SAAS,GAAG;KACZ,YAAY,GAAG;KACf,YAAY,GAAG;KACf,eAAe,SAAS;KACxB,SAAS,YAAY,IAAI,GAAG,GAAG,sBAAsB,KAAK,OAAO,QAAQ,CAAC,EAAE,IAAI,KAAK,QAAQ,QAAQ,CAAC,EAAE;IAC1G;GAEJ;EACF;CACF;CAEA,OAAO;EACL,UAAU;EACV,MAAM;EACN,QAAQ,GAAG;EACX,SAAS,GAAG;EACZ,YAAY,GAAG;EACf,YAAY,GAAG;EACf,eAAe,SAAS;CAC1B;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prompt.js","names":[],"sources":["../../../src/lib/prompt.ts"],"sourcesContent":["import { stdin, stdout } from \"node:process\";\nimport { createInterface } from \"node:readline/promises\";\n\nexport async function prompt(\n question: string,\n defaultValue?: string,\n): Promise<string> {\n const rl = createInterface({ input: stdin, output: stdout });\n const suffix = defaultValue ? ` [${defaultValue}]` : \"\";\n const answer = (await rl.question(`${question}${suffix}: `)).trim();\n rl.close();\n return answer || (defaultValue ?? \"\");\n}\n\nexport async function promptChoice(\n question: string,\n choices: string[],\n defaultValue?: string,\n): Promise<string> {\n const rl = createInterface({ input: stdin, output: stdout });\n stdout.write(`${question}\\n`);\n for (const [i, c] of choices.entries()) {\n const marker = c === defaultValue ? \"*\" : \" \";\n stdout.write(` ${marker} ${i + 1}) ${c}\\n`);\n }\n const raw = (await rl.question(`choose [${defaultValue ?? \"1\"}]: `)).trim();\n rl.close();\n if (!raw) return defaultValue ?? choices[0];\n const n = Number(raw);\n if (Number.isInteger(n) && n >= 1 && n <= choices.length)\n return choices[n - 1];\n if (choices.includes(raw)) return raw;\n return defaultValue ?? choices[0];\n}\n"],"mappings":";;;AAGA,eAAsB,OACpB,UACA,cACiB;CACjB,MAAM,KAAK,gBAAgB;EAAE,OAAO;EAAO,QAAQ;
|
|
1
|
+
{"version":3,"file":"prompt.js","names":[],"sources":["../../../src/lib/prompt.ts"],"sourcesContent":["import { stdin, stdout } from \"node:process\";\nimport { createInterface } from \"node:readline/promises\";\n\nexport async function prompt(\n question: string,\n defaultValue?: string,\n): Promise<string> {\n const rl = createInterface({ input: stdin, output: stdout });\n const suffix = defaultValue ? ` [${defaultValue}]` : \"\";\n const answer = (await rl.question(`${question}${suffix}: `)).trim();\n rl.close();\n return answer || (defaultValue ?? \"\");\n}\n\nexport async function promptChoice(\n question: string,\n choices: string[],\n defaultValue?: string,\n): Promise<string> {\n const rl = createInterface({ input: stdin, output: stdout });\n stdout.write(`${question}\\n`);\n for (const [i, c] of choices.entries()) {\n const marker = c === defaultValue ? \"*\" : \" \";\n stdout.write(` ${marker} ${i + 1}) ${c}\\n`);\n }\n const raw = (await rl.question(`choose [${defaultValue ?? \"1\"}]: `)).trim();\n rl.close();\n if (!raw) return defaultValue ?? choices[0];\n const n = Number(raw);\n if (Number.isInteger(n) && n >= 1 && n <= choices.length)\n return choices[n - 1];\n if (choices.includes(raw)) return raw;\n return defaultValue ?? choices[0];\n}\n"],"mappings":";;;AAGA,eAAsB,OACpB,UACA,cACiB;CACjB,MAAM,KAAK,gBAAgB;EAAE,OAAO;EAAO,QAAQ;CAAO,CAAC;CAC3D,MAAM,SAAS,eAAe,KAAK,aAAa,KAAK;CACrD,MAAM,UAAU,MAAM,GAAG,SAAS,GAAG,WAAW,OAAO,GAAG,GAAG,KAAK;CAClE,GAAG,MAAM;CACT,OAAO,WAAW,gBAAgB;AACpC;AAEA,eAAsB,aACpB,UACA,SACA,cACiB;CACjB,MAAM,KAAK,gBAAgB;EAAE,OAAO;EAAO,QAAQ;CAAO,CAAC;CAC3D,OAAO,MAAM,GAAG,SAAS,GAAG;CAC5B,KAAK,MAAM,CAAC,GAAG,MAAM,QAAQ,QAAQ,GAAG;EACtC,MAAM,SAAS,MAAM,eAAe,MAAM;EAC1C,OAAO,MAAM,KAAK,OAAO,GAAG,IAAI,EAAE,IAAI,EAAE,GAAG;CAC7C;CACA,MAAM,OAAO,MAAM,GAAG,SAAS,WAAW,gBAAgB,IAAI,IAAI,GAAG,KAAK;CAC1E,GAAG,MAAM;CACT,IAAI,CAAC,KAAK,OAAO,gBAAgB,QAAQ;CACzC,MAAM,IAAI,OAAO,GAAG;CACpB,IAAI,OAAO,UAAU,CAAC,KAAK,KAAK,KAAK,KAAK,QAAQ,QAChD,OAAO,QAAQ,IAAI;CACrB,IAAI,QAAQ,SAAS,GAAG,GAAG,OAAO;CAClC,OAAO,gBAAgB,QAAQ;AACjC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-dir.js","names":[],"sources":["../../../src/lib/run-dir.ts"],"sourcesContent":["import { randomBytes } from \"node:crypto\";\nimport {\n appendFileSync,\n closeSync,\n existsSync,\n fsyncSync,\n mkdirSync,\n openSync,\n readFileSync,\n renameSync,\n unlinkSync,\n writeFileSync,\n} from \"node:fs\";\nimport { dirname, join } from \"node:path\";\n\nexport function systemRunsDir(stateDir: string, systemId: string): string {\n return join(stateDir, \"runs\", systemId);\n}\n\nexport function runDir(\n stateDir: string,\n systemId: string,\n runId: string,\n): string {\n return join(systemRunsDir(stateDir, systemId), runId);\n}\n\nexport function hypothesesPath(stateDir: string, systemId: string): string {\n return join(stateDir, \"hypotheses\", `${systemId}.jsonl`);\n}\n\nexport function generateRunId(): string {\n // r-<4 hex chars><timestamp suffix>: short, sortable-ish, collision-resistant enough for our scale.\n const ts = Date.now().toString(36);\n const rand = randomBytes(2).toString(\"hex\");\n return `r-${rand}${ts.slice(-6)}`;\n}\n\nexport function ensureDir(p: string): void {\n mkdirSync(p, { recursive: true });\n}\n\n/** Atomic write: write to a temp file in the same dir, fsync, rename over the target. */\nfunction writeFileAtomic(path: string, contents: string | Uint8Array): void {\n ensureDir(dirname(path));\n const tmp = `${path}.tmp.${process.pid}.${randomBytes(3).toString(\"hex\")}`;\n const fd = openSync(tmp, \"w\", 0o644);\n try {\n writeFileSync(fd, contents);\n fsyncSync(fd);\n } finally {\n closeSync(fd);\n }\n renameSync(tmp, path);\n}\n\nexport function writeJsonAtomic(path: string, value: unknown): void {\n writeFileAtomic(path, JSON.stringify(value, null, 2) + \"\\n\");\n}\n\n/** Append a single NDJSON line. POSIX guarantees writes ≤ PIPE_BUF with O_APPEND are atomic. */\nexport function appendNdjsonLine(path: string, value: unknown): void {\n ensureDir(dirname(path));\n appendFileSync(path, JSON.stringify(value) + \"\\n\");\n}\n\nfunction readJson<T>(path: string): T {\n return JSON.parse(readFileSync(path, \"utf-8\")) as T;\n}\n\nexport function readJsonIfExists<T>(path: string): T | null {\n if (!existsSync(path)) return null;\n return readJson<T>(path);\n}\n\n/** Read an NDJSON file as an array of parsed objects. Tolerates a trailing partial line. */\nexport function readNdjson<T>(path: string): T[] {\n if (!existsSync(path)) return [];\n const text = readFileSync(path, \"utf-8\");\n const out: T[] = [];\n for (const line of text.split(\"\\n\")) {\n if (!line) continue;\n try {\n out.push(JSON.parse(line) as T);\n } catch {\n // Last line may be a partial write if a process is still appending. Skip silently.\n }\n }\n return out;\n}\n\n// --- lock file ---\n\nexport interface LockInfo {\n pid: number;\n startedAt: string;\n}\n\nfunction lockPath(runDirPath: string): string {\n return join(runDirPath, \".lock\");\n}\n\nexport function writeLock(runDirPath: string): void {\n const info: LockInfo = {\n pid: process.pid,\n startedAt: new Date().toISOString(),\n };\n writeJsonAtomic(lockPath(runDirPath), info);\n}\n\nexport function readLock(runDirPath: string): LockInfo | null {\n return readJsonIfExists<LockInfo>(lockPath(runDirPath));\n}\n\nexport function clearLock(runDirPath: string): void {\n const p = lockPath(runDirPath);\n if (existsSync(p)) unlinkSync(p);\n}\n\n/** True if the PID in the lock file is still alive on this machine. */\nexport function isPidAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code;\n return code === \"EPERM\"; // exists but we can't signal — still alive\n }\n}\n"],"mappings":";;;;AAeA,SAAgB,cAAc,UAAkB,UAA0B;
|
|
1
|
+
{"version":3,"file":"run-dir.js","names":[],"sources":["../../../src/lib/run-dir.ts"],"sourcesContent":["import { randomBytes } from \"node:crypto\";\nimport {\n appendFileSync,\n closeSync,\n existsSync,\n fsyncSync,\n mkdirSync,\n openSync,\n readFileSync,\n renameSync,\n unlinkSync,\n writeFileSync,\n} from \"node:fs\";\nimport { dirname, join } from \"node:path\";\n\nexport function systemRunsDir(stateDir: string, systemId: string): string {\n return join(stateDir, \"runs\", systemId);\n}\n\nexport function runDir(\n stateDir: string,\n systemId: string,\n runId: string,\n): string {\n return join(systemRunsDir(stateDir, systemId), runId);\n}\n\nexport function hypothesesPath(stateDir: string, systemId: string): string {\n return join(stateDir, \"hypotheses\", `${systemId}.jsonl`);\n}\n\nexport function generateRunId(): string {\n // r-<4 hex chars><timestamp suffix>: short, sortable-ish, collision-resistant enough for our scale.\n const ts = Date.now().toString(36);\n const rand = randomBytes(2).toString(\"hex\");\n return `r-${rand}${ts.slice(-6)}`;\n}\n\nexport function ensureDir(p: string): void {\n mkdirSync(p, { recursive: true });\n}\n\n/** Atomic write: write to a temp file in the same dir, fsync, rename over the target. */\nfunction writeFileAtomic(path: string, contents: string | Uint8Array): void {\n ensureDir(dirname(path));\n const tmp = `${path}.tmp.${process.pid}.${randomBytes(3).toString(\"hex\")}`;\n const fd = openSync(tmp, \"w\", 0o644);\n try {\n writeFileSync(fd, contents);\n fsyncSync(fd);\n } finally {\n closeSync(fd);\n }\n renameSync(tmp, path);\n}\n\nexport function writeJsonAtomic(path: string, value: unknown): void {\n writeFileAtomic(path, JSON.stringify(value, null, 2) + \"\\n\");\n}\n\n/** Append a single NDJSON line. POSIX guarantees writes ≤ PIPE_BUF with O_APPEND are atomic. */\nexport function appendNdjsonLine(path: string, value: unknown): void {\n ensureDir(dirname(path));\n appendFileSync(path, JSON.stringify(value) + \"\\n\");\n}\n\nfunction readJson<T>(path: string): T {\n return JSON.parse(readFileSync(path, \"utf-8\")) as T;\n}\n\nexport function readJsonIfExists<T>(path: string): T | null {\n if (!existsSync(path)) return null;\n return readJson<T>(path);\n}\n\n/** Read an NDJSON file as an array of parsed objects. Tolerates a trailing partial line. */\nexport function readNdjson<T>(path: string): T[] {\n if (!existsSync(path)) return [];\n const text = readFileSync(path, \"utf-8\");\n const out: T[] = [];\n for (const line of text.split(\"\\n\")) {\n if (!line) continue;\n try {\n out.push(JSON.parse(line) as T);\n } catch {\n // Last line may be a partial write if a process is still appending. Skip silently.\n }\n }\n return out;\n}\n\n// --- lock file ---\n\nexport interface LockInfo {\n pid: number;\n startedAt: string;\n}\n\nfunction lockPath(runDirPath: string): string {\n return join(runDirPath, \".lock\");\n}\n\nexport function writeLock(runDirPath: string): void {\n const info: LockInfo = {\n pid: process.pid,\n startedAt: new Date().toISOString(),\n };\n writeJsonAtomic(lockPath(runDirPath), info);\n}\n\nexport function readLock(runDirPath: string): LockInfo | null {\n return readJsonIfExists<LockInfo>(lockPath(runDirPath));\n}\n\nexport function clearLock(runDirPath: string): void {\n const p = lockPath(runDirPath);\n if (existsSync(p)) unlinkSync(p);\n}\n\n/** True if the PID in the lock file is still alive on this machine. */\nexport function isPidAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code;\n return code === \"EPERM\"; // exists but we can't signal — still alive\n }\n}\n"],"mappings":";;;;AAeA,SAAgB,cAAc,UAAkB,UAA0B;CACxE,OAAO,KAAK,UAAU,QAAQ,QAAQ;AACxC;AAEA,SAAgB,OACd,UACA,UACA,OACQ;CACR,OAAO,KAAK,cAAc,UAAU,QAAQ,GAAG,KAAK;AACtD;AAEA,SAAgB,eAAe,UAAkB,UAA0B;CACzE,OAAO,KAAK,UAAU,cAAc,GAAG,SAAS,OAAO;AACzD;AAEA,SAAgB,gBAAwB;CAEtC,MAAM,KAAK,KAAK,IAAI,EAAE,SAAS,EAAE;CAEjC,OAAO,KADM,YAAY,CAAC,EAAE,SAAS,KACtB,IAAI,GAAG,MAAM,EAAE;AAChC;AAEA,SAAgB,UAAU,GAAiB;CACzC,UAAU,GAAG,EAAE,WAAW,KAAK,CAAC;AAClC;;AAGA,SAAS,gBAAgB,MAAc,UAAqC;CAC1E,UAAU,QAAQ,IAAI,CAAC;CACvB,MAAM,MAAM,GAAG,KAAK,OAAO,QAAQ,IAAI,GAAG,YAAY,CAAC,EAAE,SAAS,KAAK;CACvE,MAAM,KAAK,SAAS,KAAK,KAAK,GAAK;CACnC,IAAI;EACF,cAAc,IAAI,QAAQ;EAC1B,UAAU,EAAE;CACd,UAAU;EACR,UAAU,EAAE;CACd;CACA,WAAW,KAAK,IAAI;AACtB;AAEA,SAAgB,gBAAgB,MAAc,OAAsB;CAClE,gBAAgB,MAAM,KAAK,UAAU,OAAO,MAAM,CAAC,IAAI,IAAI;AAC7D;;AAGA,SAAgB,iBAAiB,MAAc,OAAsB;CACnE,UAAU,QAAQ,IAAI,CAAC;CACvB,eAAe,MAAM,KAAK,UAAU,KAAK,IAAI,IAAI;AACnD;AAEA,SAAS,SAAY,MAAiB;CACpC,OAAO,KAAK,MAAM,aAAa,MAAM,OAAO,CAAC;AAC/C;AAEA,SAAgB,iBAAoB,MAAwB;CAC1D,IAAI,CAAC,WAAW,IAAI,GAAG,OAAO;CAC9B,OAAO,SAAY,IAAI;AACzB;;AAGA,SAAgB,WAAc,MAAmB;CAC/C,IAAI,CAAC,WAAW,IAAI,GAAG,OAAO,CAAC;CAC/B,MAAM,OAAO,aAAa,MAAM,OAAO;CACvC,MAAM,MAAW,CAAC;CAClB,KAAK,MAAM,QAAQ,KAAK,MAAM,IAAI,GAAG;EACnC,IAAI,CAAC,MAAM;EACX,IAAI;GACF,IAAI,KAAK,KAAK,MAAM,IAAI,CAAM;EAChC,QAAQ,CAER;CACF;CACA,OAAO;AACT;AASA,SAAS,SAAS,YAA4B;CAC5C,OAAO,KAAK,YAAY,OAAO;AACjC;AAEA,SAAgB,UAAU,YAA0B;CAClD,MAAM,OAAiB;EACrB,KAAK,QAAQ;EACb,4BAAW,IAAI,KAAK,GAAE,YAAY;CACpC;CACA,gBAAgB,SAAS,UAAU,GAAG,IAAI;AAC5C;AAEA,SAAgB,SAAS,YAAqC;CAC5D,OAAO,iBAA2B,SAAS,UAAU,CAAC;AACxD;AAEA,SAAgB,UAAU,YAA0B;CAClD,MAAM,IAAI,SAAS,UAAU;CAC7B,IAAI,WAAW,CAAC,GAAG,WAAW,CAAC;AACjC;;AAGA,SAAgB,WAAW,KAAsB;CAC/C,IAAI;EACF,QAAQ,KAAK,KAAK,CAAC;EACnB,OAAO;CACT,SAAS,KAAK;EAEZ,OADc,IAA8B,SAC5B;CAClB;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runner.js","names":[],"sources":["../../../src/lib/runner.ts"],"sourcesContent":["import { type ChildProcess, execSync, spawn } from \"node:child_process\";\nimport { createWriteStream, existsSync, writeFileSync } from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport { arch, hostname, platform } from \"node:os\";\nimport { extname, join } from \"node:path\";\nimport type { Readable } from \"node:stream\";\nimport type { LinearIssueLink } from \"../../shared/linear-issue.js\";\nimport {\n type CompleteEvent,\n type CrashedEvent,\n type Event,\n type ItemEvent,\n NdjsonReader,\n type PromotionEvent,\n} from \"./events.js\";\nimport {\n type ManifestFile,\n type StateFile,\n currentBaseline,\n listRuns,\n} from \"./leaderboard.js\";\nimport { resolveStateDir } from \"./paths.js\";\nimport { decidePromotion } from \"./promotion.js\";\nimport {\n appendNdjsonLine,\n clearLock,\n ensureDir,\n generateRunId,\n hypothesesPath,\n isPidAlive,\n systemRunsDir,\n readJsonIfExists,\n readLock,\n runDir,\n writeJsonAtomic,\n writeLock,\n} from \"./run-dir.js\";\nimport { type SystemDef, loadSystem, resolveEvalPath } from \"./system.js\";\n\nexport interface RunOptions {\n workspace: string;\n systemId: string;\n variant: string;\n parent: string | null;\n hypothesis: string;\n diagnostic: boolean;\n noAutoPromote: boolean;\n maxItems: number | null;\n kaizenVersion: string;\n linearIssue: LinearIssueLink | null;\n}\n\nexport interface RunResult {\n runId: string;\n status: \"complete\" | \"crashed\" | \"aborted\";\n score: number | null;\n promoted: boolean | null;\n exitCode: number;\n}\n\nconst FAILURE_K = 10;\nconst require = createRequire(import.meta.url);\n\nexport async function runExperiment(opts: RunOptions): Promise<RunResult> {\n const stateDir = resolveStateDir(opts.workspace);\n\n // 0. Reap stale runs across this system (lock present, PID dead, no terminal event).\n reapStaleRuns(stateDir, opts.systemId);\n\n // 1. Load system + resolve eval interpreter.\n const system = loadSystem(opts.workspace, opts.systemId);\n const evalAbs = resolveEvalPath(opts.workspace, system);\n if (!existsSync(evalAbs)) {\n throw new Error(\n `eval script not found at ${evalAbs} (declared as run_eval: ${system.frontmatter.run_eval} in kaizen/systems/${opts.systemId}/system.md)`,\n );\n }\n const interp = detectInterpreter(evalAbs);\n\n // 2. Generate run_id, create dir, write manifest, take lock.\n const runId = generateRunId();\n const dir = runDir(stateDir, opts.systemId, runId);\n ensureDir(dir);\n const startedAt = new Date().toISOString();\n const manifest: ManifestFile = {\n run_id: runId,\n system: opts.systemId,\n variant: opts.variant,\n parent_id: opts.parent,\n hypothesis: opts.hypothesis,\n git_sha: gitSha(opts.workspace),\n git_branch: gitBranch(opts.workspace),\n worktree_root: gitTopLevel(opts.workspace),\n git_common_dir: gitCommonDir(opts.workspace),\n eval_version: system.frontmatter.eval_version,\n dataset_version: system.frontmatter.dataset_version,\n started_at: startedAt,\n host: `${platform()}-${arch()} (${hostname()})`,\n kaizen_version: opts.kaizenVersion,\n state_dir: stateDir,\n diagnostic: opts.diagnostic,\n linear_issue_id: opts.linearIssue?.id ?? null,\n linear_issue_url: opts.linearIssue?.url ?? null,\n };\n writeJsonAtomic(join(dir, \"manifest.json\"), manifest);\n writeLock(dir);\n\n const eventsPath = join(dir, \"events.jsonl\");\n const stdoutPath = join(dir, \"stdout.log\");\n const stderrPath = join(dir, \"stderr.log\");\n\n // 3. Build initial state and write it.\n const state: StateFile & {\n system: string;\n variant: string;\n eval_version: number;\n dataset_version: string;\n started_at: string;\n updated_at: string;\n n_done: number;\n } = {\n run_id: runId,\n system: opts.systemId,\n variant: opts.variant,\n status: \"running\",\n score: null,\n n_total: null,\n n_done: 0,\n promoted: null,\n started_at: startedAt,\n updated_at: startedAt,\n ended_at: null,\n eval_version: system.frontmatter.eval_version,\n dataset_version: system.frontmatter.dataset_version,\n };\n writeJsonAtomic(join(dir, \"state.json\"), state);\n\n // 4. Spawn the eval with fd 3 piped for events.\n // For shebang scripts (cmd === evalAbs) we omit evalAbs from args, since\n // spawn already passes cmd as argv[0]. Including it would duplicate the\n // path as a positional and break argparse-based eval scripts.\n const evalArgs = [\n ...interp.preArgs,\n ...(interp.cmd === evalAbs ? [] : [evalAbs]),\n \"--variant\",\n opts.variant,\n \"--dataset\",\n system.frontmatter.dataset_version,\n \"--out-fd\",\n \"3\",\n ];\n const effectiveMax = opts.diagnostic ? 5 : opts.maxItems;\n if (effectiveMax !== null && effectiveMax !== undefined) {\n evalArgs.push(\"--max-items\", String(effectiveMax));\n }\n\n const stdoutLog = createWriteStream(stdoutPath);\n const stderrLog = createWriteStream(stderrPath);\n let stderrTail = \"\";\n\n const child: ChildProcess = spawn(interp.cmd, evalArgs, {\n cwd: opts.workspace,\n stdio: [\"ignore\", \"pipe\", \"pipe\", \"pipe\"],\n env: process.env,\n });\n\n // Tee stdout/stderr to log files. Capture last ~4KB of stderr for crash diagnostics.\n child.stdout!.on(\"data\", (chunk: Buffer) => stdoutLog.write(chunk));\n child.stderr!.on(\"data\", (chunk: Buffer) => {\n stderrLog.write(chunk);\n stderrTail = (stderrTail + chunk.toString(\"utf-8\")).slice(-4096);\n });\n\n // Event stream on fd 3. spawn(['ignore','pipe','pipe','pipe']) makes child.stdio[3] a Readable.\n const eventChan = child.stdio[3] as Readable;\n const itemEvents: ItemEvent[] = [];\n let sawComplete: CompleteEvent | null = null;\n let parseErrors = 0;\n let contractErrors = 0;\n\n const reader = new NdjsonReader(\n (e) => onEvent(e),\n (line, err) => {\n parseErrors++;\n stderrLog.write(\n `[runner] could not parse event: ${line.slice(0, 200)}\\n`,\n );\n stderrLog.write(\n `[runner] ${err instanceof Error ? err.message : String(err)}\\n`,\n );\n },\n );\n eventChan.setEncoding?.(\"utf-8\");\n eventChan.on(\"data\", (chunk) => reader.push(chunk as string | Buffer));\n // The event channel may close after the child's `exit` fires (Node docs\n // explicitly note stdio streams can outlive `exit`). We must drain it\n // before deciding terminal state — otherwise a successful run that\n // emitted a `complete` event still in the pipe buffer gets misclassified\n // as \"crashed\" because `sawComplete` is observed null.\n const eventChanEnded = new Promise<void>((resolve) => {\n eventChan.on(\"end\", () => {\n reader.end();\n resolve();\n });\n eventChan.on(\"close\", () => {\n reader.end();\n resolve();\n });\n });\n\n function onEvent(e: Event): void {\n appendNdjsonLine(eventsPath, e);\n if (e.type === \"start\") {\n const s = e;\n if (s.eval_version !== system.frontmatter.eval_version) {\n contractErrors++;\n stderrLog.write(\n `[runner] start.eval_version ${s.eval_version} does not match system eval_version ${system.frontmatter.eval_version}\\n`,\n );\n }\n if (s.dataset_version !== system.frontmatter.dataset_version) {\n contractErrors++;\n stderrLog.write(\n `[runner] start.dataset_version ${s.dataset_version} does not match system dataset_version ${system.frontmatter.dataset_version}\\n`,\n );\n }\n state.n_total = s.n;\n state.updated_at = new Date().toISOString();\n writeJsonAtomic(join(dir, \"state.json\"), state);\n } else if (e.type === \"item\") {\n const it = e;\n itemEvents.push(it);\n state.n_done = (state.n_done ?? 0) + 1;\n state.updated_at = new Date().toISOString();\n writeJsonAtomic(join(dir, \"state.json\"), state);\n } else if (e.type === \"progress\") {\n // n_done is authoritative from item events; progress is informational.\n state.updated_at = new Date().toISOString();\n writeJsonAtomic(join(dir, \"state.json\"), state);\n } else if (e.type === \"complete\") {\n sawComplete = e;\n if (state.n_total !== null && sawComplete.n !== state.n_total) {\n contractErrors++;\n stderrLog.write(\n `[runner] complete.n ${sawComplete.n} does not match start.n ${state.n_total}\\n`,\n );\n }\n state.score = sawComplete.score;\n state.updated_at = new Date().toISOString();\n writeJsonAtomic(join(dir, \"state.json\"), state);\n }\n // error/promotion/etc. — no state mutation here\n }\n\n // 5. Wait for child to exit AND for the event channel to be fully drained.\n // Both must complete before we decide terminal state — the child's exit\n // doesn't guarantee its stdio buffers have been consumed by us yet.\n const { code, signal } = await waitForExit(child);\n await eventChanEnded;\n\n // Flush logs.\n stdoutLog.end();\n stderrLog.end();\n await Promise.all([\n new Promise<void>((r) => stdoutLog.on(\"close\", () => r())),\n new Promise<void>((r) => stderrLog.on(\"close\", () => r())),\n ]);\n\n // 6. Decide terminal state.\n const endedAt = new Date().toISOString();\n if (\n code === 0 &&\n sawComplete !== null &&\n parseErrors === 0 &&\n contractErrors === 0\n ) {\n state.status = \"complete\";\n state.score = (sawComplete as CompleteEvent).score;\n // The complete event is already in events.jsonl from onEvent.\n } else {\n const crashed: CrashedEvent = {\n type: \"crashed\",\n exit_code: code,\n signal: signal ?? null,\n stderr_tail: stderrTail.slice(-2000),\n reason:\n code !== 0 && code !== null\n ? `eval exited with code ${code}`\n : signal\n ? `eval terminated by signal ${signal}`\n : parseErrors > 0\n ? `eval emitted ${parseErrors} malformed event(s)`\n : contractErrors > 0\n ? `eval emitted ${contractErrors} contract-violating event(s)`\n : sawComplete !== null\n ? \"eval emitted complete but exited non-zero\"\n : \"eval exited without emitting complete event\",\n ts: Date.now() / 1000,\n };\n appendNdjsonLine(eventsPath, crashed);\n state.status = \"crashed\";\n }\n state.ended_at = endedAt;\n state.updated_at = endedAt;\n\n // 7. Write failures.jsonl (worst-K).\n if (itemEvents.length > 0) {\n const sorted = [...itemEvents].sort((a, b) => a.score - b.score);\n const worst = sorted.slice(0, Math.min(FAILURE_K, sorted.length));\n const text =\n worst.map((it) => JSON.stringify(it)).join(\"\\n\") +\n (worst.length > 0 ? \"\\n\" : \"\");\n writeFileSync(join(dir, \"failures.jsonl\"), text);\n }\n\n // 8. Promotion (only if completed cleanly).\n let promotionEvent: PromotionEvent | null = null;\n if (state.status === \"complete\" && !opts.noAutoPromote) {\n const allRuns = listRuns(stateDir, opts.systemId).filter(\n (r) => r.run_id !== runId,\n );\n const baselineRun = currentBaseline(\n allRuns,\n system.frontmatter.eval_version,\n system.frontmatter.dataset_version,\n );\n const baseline = baselineRun\n ? {\n run_id: baselineRun.run_id,\n variant: baselineRun.variant,\n score: baselineRun.score!,\n events_path: baselineRun.events_path,\n }\n : null;\n const decision = decidePromotion(\n mapFromItems(itemEvents),\n itemEvents,\n baseline,\n { subgroupKeys: subgroupKeys(system) },\n );\n promotionEvent = { type: \"promotion\", ts: Date.now() / 1000, ...decision };\n appendNdjsonLine(eventsPath, promotionEvent);\n state.promoted = decision.promoted;\n } else if (opts.noAutoPromote) {\n state.promoted = false;\n }\n writeJsonAtomic(join(dir, \"state.json\"), state);\n\n // 9. Append hypothesis log line (every run, success or failure).\n const hypoLine = {\n run_id: runId,\n system: opts.systemId,\n variant: opts.variant,\n parent_id: opts.parent,\n hypothesis: opts.hypothesis,\n status: state.status,\n score: state.score,\n promoted: state.promoted,\n started_at: startedAt,\n ended_at: endedAt,\n eval_version: system.frontmatter.eval_version,\n dataset_version: system.frontmatter.dataset_version,\n };\n appendNdjsonLine(hypothesesPath(stateDir, opts.systemId), hypoLine);\n\n // 10. Clear lock.\n clearLock(dir);\n\n void parseErrors; // not surfaced yet; logged to stderr.log\n\n return {\n runId,\n status: state.status as \"complete\" | \"crashed\" | \"aborted\",\n score: state.score,\n promoted: state.promoted ?? null,\n exitCode: state.status === \"complete\" ? 0 : 1,\n };\n}\n\n// --- helpers ---\n\ninterface InterpreterChoice {\n cmd: string;\n preArgs: string[];\n}\n\nfunction detectInterpreter(evalPath: string): InterpreterChoice {\n const ext = extname(evalPath).toLowerCase();\n if (ext === \".py\") return { cmd: \"python3\", preArgs: [] };\n if (ext === \".js\" || ext === \".mjs\" || ext === \".cjs\")\n return { cmd: \"node\", preArgs: [] };\n if (ext === \".ts\" || ext === \".tsx\" || ext === \".mts\" || ext === \".cts\") {\n return {\n cmd: process.execPath,\n preArgs: [\"--import\", require.resolve(\"tsx\")],\n };\n }\n // Default: assume executable with shebang.\n return { cmd: evalPath, preArgs: [] };\n}\n\nfunction waitForExit(\n child: ChildProcess,\n): Promise<{ code: number | null; signal: NodeJS.Signals | null }> {\n return new Promise((resolve) => {\n child.on(\"exit\", (code: number | null, signal: NodeJS.Signals | null) =>\n resolve({ code, signal }),\n );\n });\n}\n\nfunction gitSha(cwd: string): string | null {\n try {\n return (\n execSync(\"git rev-parse HEAD\", {\n cwd,\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n })\n .toString()\n .trim() || null\n );\n } catch {\n return null;\n }\n}\n\nfunction gitBranch(cwd: string): string | null {\n try {\n return (\n execSync(\"git rev-parse --abbrev-ref HEAD\", {\n cwd,\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n })\n .toString()\n .trim() || null\n );\n } catch {\n return null;\n }\n}\n\nfunction gitTopLevel(cwd: string): string | null {\n try {\n return (\n execSync(\"git rev-parse --show-toplevel\", {\n cwd,\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n })\n .toString()\n .trim() || null\n );\n } catch {\n return null;\n }\n}\n\nfunction gitCommonDir(cwd: string): string | null {\n try {\n return (\n execSync(\"git rev-parse --git-common-dir\", {\n cwd,\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n })\n .toString()\n .trim() || null\n );\n } catch {\n return null;\n }\n}\n\nfunction mapFromItems(items: ItemEvent[]): Map<string, number> {\n const m = new Map<string, number>();\n for (const it of items) m.set(it.id, it.score);\n return m;\n}\n\nfunction subgroupKeys(system: SystemDef): string[] {\n const sg = (\n system.frontmatter as {\n subgroups?: Array<{ field?: string; name?: string }>;\n }\n ).subgroups;\n if (!Array.isArray(sg)) return [];\n return sg.map((s) => s.field ?? s.name ?? \"\").filter(Boolean);\n}\n\n/**\n * Sweep stale runs whose lock points to a dead PID and which never recorded a terminal event.\n * Mark them `crashed` with reason \"supervisor died\" so the dashboard / log don't show ghosts.\n */\nexport function reapStaleRuns(stateDir: string, systemId: string): void {\n const dir = systemRunsDir(stateDir, systemId);\n if (!existsSync(dir)) return;\n for (const run of listRuns(stateDir, systemId)) {\n if (run.status !== \"running\") continue;\n const lock = readLock(join(dir, run.run_id));\n if (!lock) continue;\n if (isPidAlive(lock.pid)) continue;\n const reapedEvent: CrashedEvent = {\n type: \"crashed\",\n exit_code: null,\n signal: null,\n reason: `runner pid ${lock.pid} died without writing a terminal event; reaped`,\n ts: Date.now() / 1000,\n };\n appendNdjsonLine(run.events_path, reapedEvent);\n\n const state = readJsonIfExists<StateFile>(run.state_path);\n if (state) {\n state.status = \"crashed\";\n state.ended_at = new Date().toISOString();\n writeJsonAtomic(run.state_path, state);\n }\n clearLock(join(dir, run.run_id));\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"runner.js","names":[],"sources":["../../../src/lib/runner.ts"],"sourcesContent":["import { type ChildProcess, execSync, spawn } from \"node:child_process\";\nimport { createWriteStream, existsSync, writeFileSync } from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport { arch, hostname, platform } from \"node:os\";\nimport { extname, join } from \"node:path\";\nimport type { Readable } from \"node:stream\";\nimport type { LinearIssueLink } from \"../../shared/linear-issue.js\";\nimport {\n type CompleteEvent,\n type CrashedEvent,\n type Event,\n type ItemEvent,\n NdjsonReader,\n type PromotionEvent,\n} from \"./events.js\";\nimport {\n type ManifestFile,\n type StateFile,\n currentBaseline,\n listRuns,\n} from \"./leaderboard.js\";\nimport { resolveStateDir } from \"./paths.js\";\nimport { decidePromotion } from \"./promotion.js\";\nimport {\n appendNdjsonLine,\n clearLock,\n ensureDir,\n generateRunId,\n hypothesesPath,\n isPidAlive,\n systemRunsDir,\n readJsonIfExists,\n readLock,\n runDir,\n writeJsonAtomic,\n writeLock,\n} from \"./run-dir.js\";\nimport { type SystemDef, loadSystem, resolveEvalPath } from \"./system.js\";\n\nexport interface RunOptions {\n workspace: string;\n systemId: string;\n variant: string;\n parent: string | null;\n hypothesis: string;\n diagnostic: boolean;\n noAutoPromote: boolean;\n maxItems: number | null;\n kaizenVersion: string;\n linearIssue: LinearIssueLink | null;\n}\n\nexport interface RunResult {\n runId: string;\n status: \"complete\" | \"crashed\" | \"aborted\";\n score: number | null;\n promoted: boolean | null;\n exitCode: number;\n}\n\nconst FAILURE_K = 10;\nconst require = createRequire(import.meta.url);\n\nexport async function runExperiment(opts: RunOptions): Promise<RunResult> {\n const stateDir = resolveStateDir(opts.workspace);\n\n // 0. Reap stale runs across this system (lock present, PID dead, no terminal event).\n reapStaleRuns(stateDir, opts.systemId);\n\n // 1. Load system + resolve eval interpreter.\n const system = loadSystem(opts.workspace, opts.systemId);\n const evalAbs = resolveEvalPath(opts.workspace, system);\n if (!existsSync(evalAbs)) {\n throw new Error(\n `eval script not found at ${evalAbs} (declared as run_eval: ${system.frontmatter.run_eval} in kaizen/systems/${opts.systemId}/system.md)`,\n );\n }\n const interp = detectInterpreter(evalAbs);\n\n // 2. Generate run_id, create dir, write manifest, take lock.\n const runId = generateRunId();\n const dir = runDir(stateDir, opts.systemId, runId);\n ensureDir(dir);\n const startedAt = new Date().toISOString();\n const manifest: ManifestFile = {\n run_id: runId,\n system: opts.systemId,\n variant: opts.variant,\n parent_id: opts.parent,\n hypothesis: opts.hypothesis,\n git_sha: gitSha(opts.workspace),\n git_branch: gitBranch(opts.workspace),\n worktree_root: gitTopLevel(opts.workspace),\n git_common_dir: gitCommonDir(opts.workspace),\n eval_version: system.frontmatter.eval_version,\n dataset_version: system.frontmatter.dataset_version,\n started_at: startedAt,\n host: `${platform()}-${arch()} (${hostname()})`,\n kaizen_version: opts.kaizenVersion,\n state_dir: stateDir,\n diagnostic: opts.diagnostic,\n linear_issue_id: opts.linearIssue?.id ?? null,\n linear_issue_url: opts.linearIssue?.url ?? null,\n };\n writeJsonAtomic(join(dir, \"manifest.json\"), manifest);\n writeLock(dir);\n\n const eventsPath = join(dir, \"events.jsonl\");\n const stdoutPath = join(dir, \"stdout.log\");\n const stderrPath = join(dir, \"stderr.log\");\n\n // 3. Build initial state and write it.\n const state: StateFile & {\n system: string;\n variant: string;\n eval_version: number;\n dataset_version: string;\n started_at: string;\n updated_at: string;\n n_done: number;\n } = {\n run_id: runId,\n system: opts.systemId,\n variant: opts.variant,\n status: \"running\",\n score: null,\n n_total: null,\n n_done: 0,\n promoted: null,\n started_at: startedAt,\n updated_at: startedAt,\n ended_at: null,\n eval_version: system.frontmatter.eval_version,\n dataset_version: system.frontmatter.dataset_version,\n };\n writeJsonAtomic(join(dir, \"state.json\"), state);\n\n // 4. Spawn the eval with fd 3 piped for events.\n // For shebang scripts (cmd === evalAbs) we omit evalAbs from args, since\n // spawn already passes cmd as argv[0]. Including it would duplicate the\n // path as a positional and break argparse-based eval scripts.\n const evalArgs = [\n ...interp.preArgs,\n ...(interp.cmd === evalAbs ? [] : [evalAbs]),\n \"--variant\",\n opts.variant,\n \"--dataset\",\n system.frontmatter.dataset_version,\n \"--out-fd\",\n \"3\",\n ];\n const effectiveMax = opts.diagnostic ? 5 : opts.maxItems;\n if (effectiveMax !== null && effectiveMax !== undefined) {\n evalArgs.push(\"--max-items\", String(effectiveMax));\n }\n\n const stdoutLog = createWriteStream(stdoutPath);\n const stderrLog = createWriteStream(stderrPath);\n let stderrTail = \"\";\n\n const child: ChildProcess = spawn(interp.cmd, evalArgs, {\n cwd: opts.workspace,\n stdio: [\"ignore\", \"pipe\", \"pipe\", \"pipe\"],\n env: process.env,\n });\n\n // Tee stdout/stderr to log files. Capture last ~4KB of stderr for crash diagnostics.\n child.stdout!.on(\"data\", (chunk: Buffer) => stdoutLog.write(chunk));\n child.stderr!.on(\"data\", (chunk: Buffer) => {\n stderrLog.write(chunk);\n stderrTail = (stderrTail + chunk.toString(\"utf-8\")).slice(-4096);\n });\n\n // Event stream on fd 3. spawn(['ignore','pipe','pipe','pipe']) makes child.stdio[3] a Readable.\n const eventChan = child.stdio[3] as Readable;\n const itemEvents: ItemEvent[] = [];\n let sawComplete: CompleteEvent | null = null;\n let parseErrors = 0;\n let contractErrors = 0;\n\n const reader = new NdjsonReader(\n (e) => onEvent(e),\n (line, err) => {\n parseErrors++;\n stderrLog.write(\n `[runner] could not parse event: ${line.slice(0, 200)}\\n`,\n );\n stderrLog.write(\n `[runner] ${err instanceof Error ? err.message : String(err)}\\n`,\n );\n },\n );\n eventChan.setEncoding?.(\"utf-8\");\n eventChan.on(\"data\", (chunk) => reader.push(chunk as string | Buffer));\n // The event channel may close after the child's `exit` fires (Node docs\n // explicitly note stdio streams can outlive `exit`). We must drain it\n // before deciding terminal state — otherwise a successful run that\n // emitted a `complete` event still in the pipe buffer gets misclassified\n // as \"crashed\" because `sawComplete` is observed null.\n const eventChanEnded = new Promise<void>((resolve) => {\n eventChan.on(\"end\", () => {\n reader.end();\n resolve();\n });\n eventChan.on(\"close\", () => {\n reader.end();\n resolve();\n });\n });\n\n function onEvent(e: Event): void {\n appendNdjsonLine(eventsPath, e);\n if (e.type === \"start\") {\n const s = e;\n if (s.eval_version !== system.frontmatter.eval_version) {\n contractErrors++;\n stderrLog.write(\n `[runner] start.eval_version ${s.eval_version} does not match system eval_version ${system.frontmatter.eval_version}\\n`,\n );\n }\n if (s.dataset_version !== system.frontmatter.dataset_version) {\n contractErrors++;\n stderrLog.write(\n `[runner] start.dataset_version ${s.dataset_version} does not match system dataset_version ${system.frontmatter.dataset_version}\\n`,\n );\n }\n state.n_total = s.n;\n state.updated_at = new Date().toISOString();\n writeJsonAtomic(join(dir, \"state.json\"), state);\n } else if (e.type === \"item\") {\n const it = e;\n itemEvents.push(it);\n state.n_done = (state.n_done ?? 0) + 1;\n state.updated_at = new Date().toISOString();\n writeJsonAtomic(join(dir, \"state.json\"), state);\n } else if (e.type === \"progress\") {\n // n_done is authoritative from item events; progress is informational.\n state.updated_at = new Date().toISOString();\n writeJsonAtomic(join(dir, \"state.json\"), state);\n } else if (e.type === \"complete\") {\n sawComplete = e;\n if (state.n_total !== null && sawComplete.n !== state.n_total) {\n contractErrors++;\n stderrLog.write(\n `[runner] complete.n ${sawComplete.n} does not match start.n ${state.n_total}\\n`,\n );\n }\n state.score = sawComplete.score;\n state.updated_at = new Date().toISOString();\n writeJsonAtomic(join(dir, \"state.json\"), state);\n }\n // error/promotion/etc. — no state mutation here\n }\n\n // 5. Wait for child to exit AND for the event channel to be fully drained.\n // Both must complete before we decide terminal state — the child's exit\n // doesn't guarantee its stdio buffers have been consumed by us yet.\n const { code, signal } = await waitForExit(child);\n await eventChanEnded;\n\n // Flush logs.\n stdoutLog.end();\n stderrLog.end();\n await Promise.all([\n new Promise<void>((r) => stdoutLog.on(\"close\", () => r())),\n new Promise<void>((r) => stderrLog.on(\"close\", () => r())),\n ]);\n\n // 6. Decide terminal state.\n const endedAt = new Date().toISOString();\n if (\n code === 0 &&\n sawComplete !== null &&\n parseErrors === 0 &&\n contractErrors === 0\n ) {\n state.status = \"complete\";\n state.score = (sawComplete as CompleteEvent).score;\n // The complete event is already in events.jsonl from onEvent.\n } else {\n const crashed: CrashedEvent = {\n type: \"crashed\",\n exit_code: code,\n signal: signal ?? null,\n stderr_tail: stderrTail.slice(-2000),\n reason:\n code !== 0 && code !== null\n ? `eval exited with code ${code}`\n : signal\n ? `eval terminated by signal ${signal}`\n : parseErrors > 0\n ? `eval emitted ${parseErrors} malformed event(s)`\n : contractErrors > 0\n ? `eval emitted ${contractErrors} contract-violating event(s)`\n : sawComplete !== null\n ? \"eval emitted complete but exited non-zero\"\n : \"eval exited without emitting complete event\",\n ts: Date.now() / 1000,\n };\n appendNdjsonLine(eventsPath, crashed);\n state.status = \"crashed\";\n }\n state.ended_at = endedAt;\n state.updated_at = endedAt;\n\n // 7. Write failures.jsonl (worst-K).\n if (itemEvents.length > 0) {\n const sorted = [...itemEvents].sort((a, b) => a.score - b.score);\n const worst = sorted.slice(0, Math.min(FAILURE_K, sorted.length));\n const text =\n worst.map((it) => JSON.stringify(it)).join(\"\\n\") +\n (worst.length > 0 ? \"\\n\" : \"\");\n writeFileSync(join(dir, \"failures.jsonl\"), text);\n }\n\n // 8. Promotion (only if completed cleanly).\n let promotionEvent: PromotionEvent | null = null;\n if (state.status === \"complete\" && !opts.noAutoPromote) {\n const allRuns = listRuns(stateDir, opts.systemId).filter(\n (r) => r.run_id !== runId,\n );\n const baselineRun = currentBaseline(\n allRuns,\n system.frontmatter.eval_version,\n system.frontmatter.dataset_version,\n );\n const baseline = baselineRun\n ? {\n run_id: baselineRun.run_id,\n variant: baselineRun.variant,\n score: baselineRun.score!,\n events_path: baselineRun.events_path,\n }\n : null;\n const decision = decidePromotion(\n mapFromItems(itemEvents),\n itemEvents,\n baseline,\n { subgroupKeys: subgroupKeys(system) },\n );\n promotionEvent = { type: \"promotion\", ts: Date.now() / 1000, ...decision };\n appendNdjsonLine(eventsPath, promotionEvent);\n state.promoted = decision.promoted;\n } else if (opts.noAutoPromote) {\n state.promoted = false;\n }\n writeJsonAtomic(join(dir, \"state.json\"), state);\n\n // 9. Append hypothesis log line (every run, success or failure).\n const hypoLine = {\n run_id: runId,\n system: opts.systemId,\n variant: opts.variant,\n parent_id: opts.parent,\n hypothesis: opts.hypothesis,\n status: state.status,\n score: state.score,\n promoted: state.promoted,\n started_at: startedAt,\n ended_at: endedAt,\n eval_version: system.frontmatter.eval_version,\n dataset_version: system.frontmatter.dataset_version,\n };\n appendNdjsonLine(hypothesesPath(stateDir, opts.systemId), hypoLine);\n\n // 10. Clear lock.\n clearLock(dir);\n\n void parseErrors; // not surfaced yet; logged to stderr.log\n\n return {\n runId,\n status: state.status as \"complete\" | \"crashed\" | \"aborted\",\n score: state.score,\n promoted: state.promoted ?? null,\n exitCode: state.status === \"complete\" ? 0 : 1,\n };\n}\n\n// --- helpers ---\n\ninterface InterpreterChoice {\n cmd: string;\n preArgs: string[];\n}\n\nfunction detectInterpreter(evalPath: string): InterpreterChoice {\n const ext = extname(evalPath).toLowerCase();\n if (ext === \".py\") return { cmd: \"python3\", preArgs: [] };\n if (ext === \".js\" || ext === \".mjs\" || ext === \".cjs\")\n return { cmd: \"node\", preArgs: [] };\n if (ext === \".ts\" || ext === \".tsx\" || ext === \".mts\" || ext === \".cts\") {\n return {\n cmd: process.execPath,\n preArgs: [\"--import\", require.resolve(\"tsx\")],\n };\n }\n // Default: assume executable with shebang.\n return { cmd: evalPath, preArgs: [] };\n}\n\nfunction waitForExit(\n child: ChildProcess,\n): Promise<{ code: number | null; signal: NodeJS.Signals | null }> {\n return new Promise((resolve) => {\n child.on(\"exit\", (code: number | null, signal: NodeJS.Signals | null) =>\n resolve({ code, signal }),\n );\n });\n}\n\nfunction gitSha(cwd: string): string | null {\n try {\n return (\n execSync(\"git rev-parse HEAD\", {\n cwd,\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n })\n .toString()\n .trim() || null\n );\n } catch {\n return null;\n }\n}\n\nfunction gitBranch(cwd: string): string | null {\n try {\n return (\n execSync(\"git rev-parse --abbrev-ref HEAD\", {\n cwd,\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n })\n .toString()\n .trim() || null\n );\n } catch {\n return null;\n }\n}\n\nfunction gitTopLevel(cwd: string): string | null {\n try {\n return (\n execSync(\"git rev-parse --show-toplevel\", {\n cwd,\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n })\n .toString()\n .trim() || null\n );\n } catch {\n return null;\n }\n}\n\nfunction gitCommonDir(cwd: string): string | null {\n try {\n return (\n execSync(\"git rev-parse --git-common-dir\", {\n cwd,\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n })\n .toString()\n .trim() || null\n );\n } catch {\n return null;\n }\n}\n\nfunction mapFromItems(items: ItemEvent[]): Map<string, number> {\n const m = new Map<string, number>();\n for (const it of items) m.set(it.id, it.score);\n return m;\n}\n\nfunction subgroupKeys(system: SystemDef): string[] {\n const sg = (\n system.frontmatter as {\n subgroups?: Array<{ field?: string; name?: string }>;\n }\n ).subgroups;\n if (!Array.isArray(sg)) return [];\n return sg.map((s) => s.field ?? s.name ?? \"\").filter(Boolean);\n}\n\n/**\n * Sweep stale runs whose lock points to a dead PID and which never recorded a terminal event.\n * Mark them `crashed` with reason \"supervisor died\" so the dashboard / log don't show ghosts.\n */\nexport function reapStaleRuns(stateDir: string, systemId: string): void {\n const dir = systemRunsDir(stateDir, systemId);\n if (!existsSync(dir)) return;\n for (const run of listRuns(stateDir, systemId)) {\n if (run.status !== \"running\") continue;\n const lock = readLock(join(dir, run.run_id));\n if (!lock) continue;\n if (isPidAlive(lock.pid)) continue;\n const reapedEvent: CrashedEvent = {\n type: \"crashed\",\n exit_code: null,\n signal: null,\n reason: `runner pid ${lock.pid} died without writing a terminal event; reaped`,\n ts: Date.now() / 1000,\n };\n appendNdjsonLine(run.events_path, reapedEvent);\n\n const state = readJsonIfExists<StateFile>(run.state_path);\n if (state) {\n state.status = \"crashed\";\n state.ended_at = new Date().toISOString();\n writeJsonAtomic(run.state_path, state);\n }\n clearLock(join(dir, run.run_id));\n }\n}\n"],"mappings":";;;;;;;;;;;;AA4DA,MAAM,YAAY;AAClB,MAAM,UAAU,cAAc,OAAO,KAAK,GAAG;AAE7C,eAAsB,cAAc,MAAsC;CACxE,MAAM,WAAW,gBAAgB,KAAK,SAAS;CAG/C,cAAc,UAAU,KAAK,QAAQ;CAGrC,MAAM,SAAS,WAAW,KAAK,WAAW,KAAK,QAAQ;CACvD,MAAM,UAAU,gBAAgB,KAAK,WAAW,MAAM;CACtD,IAAI,CAAC,WAAW,OAAO,GACrB,MAAM,IAAI,MACR,4BAA4B,QAAQ,0BAA0B,OAAO,YAAY,SAAS,qBAAqB,KAAK,SAAS,YAC/H;CAEF,MAAM,SAAS,kBAAkB,OAAO;CAGxC,MAAM,QAAQ,cAAc;CAC5B,MAAM,MAAM,OAAO,UAAU,KAAK,UAAU,KAAK;CACjD,UAAU,GAAG;CACb,MAAM,6BAAY,IAAI,KAAK,GAAE,YAAY;CACzC,MAAM,WAAyB;EAC7B,QAAQ;EACR,QAAQ,KAAK;EACb,SAAS,KAAK;EACd,WAAW,KAAK;EAChB,YAAY,KAAK;EACjB,SAAS,OAAO,KAAK,SAAS;EAC9B,YAAY,UAAU,KAAK,SAAS;EACpC,eAAe,YAAY,KAAK,SAAS;EACzC,gBAAgB,aAAa,KAAK,SAAS;EAC3C,cAAc,OAAO,YAAY;EACjC,iBAAiB,OAAO,YAAY;EACpC,YAAY;EACZ,MAAM,GAAG,SAAS,EAAE,GAAG,KAAK,EAAE,IAAI,SAAS,EAAE;EAC7C,gBAAgB,KAAK;EACrB,WAAW;EACX,YAAY,KAAK;EACjB,iBAAiB,KAAK,aAAa,MAAM;EACzC,kBAAkB,KAAK,aAAa,OAAO;CAC7C;CACA,gBAAgB,KAAK,KAAK,eAAe,GAAG,QAAQ;CACpD,UAAU,GAAG;CAEb,MAAM,aAAa,KAAK,KAAK,cAAc;CAC3C,MAAM,aAAa,KAAK,KAAK,YAAY;CACzC,MAAM,aAAa,KAAK,KAAK,YAAY;CAGzC,MAAM,QAQF;EACF,QAAQ;EACR,QAAQ,KAAK;EACb,SAAS,KAAK;EACd,QAAQ;EACR,OAAO;EACP,SAAS;EACT,QAAQ;EACR,UAAU;EACV,YAAY;EACZ,YAAY;EACZ,UAAU;EACV,cAAc,OAAO,YAAY;EACjC,iBAAiB,OAAO,YAAY;CACtC;CACA,gBAAgB,KAAK,KAAK,YAAY,GAAG,KAAK;CAM9C,MAAM,WAAW;EACf,GAAG,OAAO;EACV,GAAI,OAAO,QAAQ,UAAU,CAAC,IAAI,CAAC,OAAO;EAC1C;EACA,KAAK;EACL;EACA,OAAO,YAAY;EACnB;EACA;CACF;CACA,MAAM,eAAe,KAAK,aAAa,IAAI,KAAK;CAChD,IAAI,iBAAiB,QAAQ,iBAAiB,KAAA,GAC5C,SAAS,KAAK,eAAe,OAAO,YAAY,CAAC;CAGnD,MAAM,YAAY,kBAAkB,UAAU;CAC9C,MAAM,YAAY,kBAAkB,UAAU;CAC9C,IAAI,aAAa;CAEjB,MAAM,QAAsB,MAAM,OAAO,KAAK,UAAU;EACtD,KAAK,KAAK;EACV,OAAO;GAAC;GAAU;GAAQ;GAAQ;EAAM;EACxC,KAAK,QAAQ;CACf,CAAC;CAGD,MAAM,OAAQ,GAAG,SAAS,UAAkB,UAAU,MAAM,KAAK,CAAC;CAClE,MAAM,OAAQ,GAAG,SAAS,UAAkB;EAC1C,UAAU,MAAM,KAAK;EACrB,cAAc,aAAa,MAAM,SAAS,OAAO,GAAG,MAAM,KAAK;CACjE,CAAC;CAGD,MAAM,YAAY,MAAM,MAAM;CAC9B,MAAM,aAA0B,CAAC;CACjC,IAAI,cAAoC;CACxC,IAAI,cAAc;CAClB,IAAI,iBAAiB;CAErB,MAAM,SAAS,IAAI,cAChB,MAAM,QAAQ,CAAC,IACf,MAAM,QAAQ;EACb;EACA,UAAU,MACR,mCAAmC,KAAK,MAAM,GAAG,GAAG,EAAE,GACxD;EACA,UAAU,MACR,YAAY,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,EAAE,GAC/D;CACF,CACF;CACA,UAAU,cAAc,OAAO;CAC/B,UAAU,GAAG,SAAS,UAAU,OAAO,KAAK,KAAwB,CAAC;CAMrE,MAAM,iBAAiB,IAAI,SAAe,YAAY;EACpD,UAAU,GAAG,aAAa;GACxB,OAAO,IAAI;GACX,QAAQ;EACV,CAAC;EACD,UAAU,GAAG,eAAe;GAC1B,OAAO,IAAI;GACX,QAAQ;EACV,CAAC;CACH,CAAC;CAED,SAAS,QAAQ,GAAgB;EAC/B,iBAAiB,YAAY,CAAC;EAC9B,IAAI,EAAE,SAAS,SAAS;GACtB,MAAM,IAAI;GACV,IAAI,EAAE,iBAAiB,OAAO,YAAY,cAAc;IACtD;IACA,UAAU,MACR,+BAA+B,EAAE,aAAa,sCAAsC,OAAO,YAAY,aAAa,GACtH;GACF;GACA,IAAI,EAAE,oBAAoB,OAAO,YAAY,iBAAiB;IAC5D;IACA,UAAU,MACR,kCAAkC,EAAE,gBAAgB,yCAAyC,OAAO,YAAY,gBAAgB,GAClI;GACF;GACA,MAAM,UAAU,EAAE;GAClB,MAAM,8BAAa,IAAI,KAAK,GAAE,YAAY;GAC1C,gBAAgB,KAAK,KAAK,YAAY,GAAG,KAAK;EAChD,OAAO,IAAI,EAAE,SAAS,QAAQ;GAC5B,MAAM,KAAK;GACX,WAAW,KAAK,EAAE;GAClB,MAAM,UAAU,MAAM,UAAU,KAAK;GACrC,MAAM,8BAAa,IAAI,KAAK,GAAE,YAAY;GAC1C,gBAAgB,KAAK,KAAK,YAAY,GAAG,KAAK;EAChD,OAAO,IAAI,EAAE,SAAS,YAAY;GAEhC,MAAM,8BAAa,IAAI,KAAK,GAAE,YAAY;GAC1C,gBAAgB,KAAK,KAAK,YAAY,GAAG,KAAK;EAChD,OAAO,IAAI,EAAE,SAAS,YAAY;GAChC,cAAc;GACd,IAAI,MAAM,YAAY,QAAQ,YAAY,MAAM,MAAM,SAAS;IAC7D;IACA,UAAU,MACR,uBAAuB,YAAY,EAAE,0BAA0B,MAAM,QAAQ,GAC/E;GACF;GACA,MAAM,QAAQ,YAAY;GAC1B,MAAM,8BAAa,IAAI,KAAK,GAAE,YAAY;GAC1C,gBAAgB,KAAK,KAAK,YAAY,GAAG,KAAK;EAChD;CAEF;CAKA,MAAM,EAAE,MAAM,WAAW,MAAM,YAAY,KAAK;CAChD,MAAM;CAGN,UAAU,IAAI;CACd,UAAU,IAAI;CACd,MAAM,QAAQ,IAAI,CAChB,IAAI,SAAe,MAAM,UAAU,GAAG,eAAe,EAAE,CAAC,CAAC,GACzD,IAAI,SAAe,MAAM,UAAU,GAAG,eAAe,EAAE,CAAC,CAAC,CAC3D,CAAC;CAGD,MAAM,2BAAU,IAAI,KAAK,GAAE,YAAY;CACvC,IACE,SAAS,KACT,gBAAgB,QAChB,gBAAgB,KAChB,mBAAmB,GACnB;EACA,MAAM,SAAS;EACf,MAAM,QAAS,YAA8B;CAE/C,OAAO;EAoBL,iBAAiB,YAAY;GAlB3B,MAAM;GACN,WAAW;GACX,QAAQ,UAAU;GAClB,aAAa,WAAW,MAAM,IAAK;GACnC,QACE,SAAS,KAAK,SAAS,OACnB,yBAAyB,SACzB,SACE,6BAA6B,WAC7B,cAAc,IACZ,gBAAgB,YAAY,uBAC5B,iBAAiB,IACf,gBAAgB,eAAe,gCAC/B,gBAAgB,OACd,8CACA;GACd,IAAI,KAAK,IAAI,IAAI;EAEgB,CAAC;EACpC,MAAM,SAAS;CACjB;CACA,MAAM,WAAW;CACjB,MAAM,aAAa;CAGnB,IAAI,WAAW,SAAS,GAAG;EACzB,MAAM,SAAS,CAAC,GAAG,UAAU,EAAE,MAAM,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK;EAC/D,MAAM,QAAQ,OAAO,MAAM,GAAG,KAAK,IAAI,WAAW,OAAO,MAAM,CAAC;EAChE,MAAM,OACJ,MAAM,KAAK,OAAO,KAAK,UAAU,EAAE,CAAC,EAAE,KAAK,IAAI,KAC9C,MAAM,SAAS,IAAI,OAAO;EAC7B,cAAc,KAAK,KAAK,gBAAgB,GAAG,IAAI;CACjD;CAGA,IAAI,iBAAwC;CAC5C,IAAI,MAAM,WAAW,cAAc,CAAC,KAAK,eAAe;EAItD,MAAM,cAAc,gBAHJ,SAAS,UAAU,KAAK,QAAQ,EAAE,QAC/C,MAAM,EAAE,WAAW,KAGd,GACN,OAAO,YAAY,cACnB,OAAO,YAAY,eACrB;EACA,MAAM,WAAW,cACb;GACE,QAAQ,YAAY;GACpB,SAAS,YAAY;GACrB,OAAO,YAAY;GACnB,aAAa,YAAY;EAC3B,IACA;EACJ,MAAM,WAAW,gBACf,aAAa,UAAU,GACvB,YACA,UACA,EAAE,cAAc,aAAa,MAAM,EAAE,CACvC;EACA,iBAAiB;GAAE,MAAM;GAAa,IAAI,KAAK,IAAI,IAAI;GAAM,GAAG;EAAS;EACzE,iBAAiB,YAAY,cAAc;EAC3C,MAAM,WAAW,SAAS;CAC5B,OAAO,IAAI,KAAK,eACd,MAAM,WAAW;CAEnB,gBAAgB,KAAK,KAAK,YAAY,GAAG,KAAK;CAG9C,MAAM,WAAW;EACf,QAAQ;EACR,QAAQ,KAAK;EACb,SAAS,KAAK;EACd,WAAW,KAAK;EAChB,YAAY,KAAK;EACjB,QAAQ,MAAM;EACd,OAAO,MAAM;EACb,UAAU,MAAM;EAChB,YAAY;EACZ,UAAU;EACV,cAAc,OAAO,YAAY;EACjC,iBAAiB,OAAO,YAAY;CACtC;CACA,iBAAiB,eAAe,UAAU,KAAK,QAAQ,GAAG,QAAQ;CAGlE,UAAU,GAAG;CAIb,OAAO;EACL;EACA,QAAQ,MAAM;EACd,OAAO,MAAM;EACb,UAAU,MAAM,YAAY;EAC5B,UAAU,MAAM,WAAW,aAAa,IAAI;CAC9C;AACF;AASA,SAAS,kBAAkB,UAAqC;CAC9D,MAAM,MAAM,QAAQ,QAAQ,EAAE,YAAY;CAC1C,IAAI,QAAQ,OAAO,OAAO;EAAE,KAAK;EAAW,SAAS,CAAC;CAAE;CACxD,IAAI,QAAQ,SAAS,QAAQ,UAAU,QAAQ,QAC7C,OAAO;EAAE,KAAK;EAAQ,SAAS,CAAC;CAAE;CACpC,IAAI,QAAQ,SAAS,QAAQ,UAAU,QAAQ,UAAU,QAAQ,QAC/D,OAAO;EACL,KAAK,QAAQ;EACb,SAAS,CAAC,YAAY,QAAQ,QAAQ,KAAK,CAAC;CAC9C;CAGF,OAAO;EAAE,KAAK;EAAU,SAAS,CAAC;CAAE;AACtC;AAEA,SAAS,YACP,OACiE;CACjE,OAAO,IAAI,SAAS,YAAY;EAC9B,MAAM,GAAG,SAAS,MAAqB,WACrC,QAAQ;GAAE;GAAM;EAAO,CAAC,CAC1B;CACF,CAAC;AACH;AAEA,SAAS,OAAO,KAA4B;CAC1C,IAAI;EACF,OACE,SAAS,sBAAsB;GAC7B;GACA,OAAO;IAAC;IAAU;IAAQ;GAAQ;EACpC,CAAC,EACE,SAAS,EACT,KAAK,KAAK;CAEjB,QAAQ;EACN,OAAO;CACT;AACF;AAEA,SAAS,UAAU,KAA4B;CAC7C,IAAI;EACF,OACE,SAAS,mCAAmC;GAC1C;GACA,OAAO;IAAC;IAAU;IAAQ;GAAQ;EACpC,CAAC,EACE,SAAS,EACT,KAAK,KAAK;CAEjB,QAAQ;EACN,OAAO;CACT;AACF;AAEA,SAAS,YAAY,KAA4B;CAC/C,IAAI;EACF,OACE,SAAS,iCAAiC;GACxC;GACA,OAAO;IAAC;IAAU;IAAQ;GAAQ;EACpC,CAAC,EACE,SAAS,EACT,KAAK,KAAK;CAEjB,QAAQ;EACN,OAAO;CACT;AACF;AAEA,SAAS,aAAa,KAA4B;CAChD,IAAI;EACF,OACE,SAAS,kCAAkC;GACzC;GACA,OAAO;IAAC;IAAU;IAAQ;GAAQ;EACpC,CAAC,EACE,SAAS,EACT,KAAK,KAAK;CAEjB,QAAQ;EACN,OAAO;CACT;AACF;AAEA,SAAS,aAAa,OAAyC;CAC7D,MAAM,oBAAI,IAAI,IAAoB;CAClC,KAAK,MAAM,MAAM,OAAO,EAAE,IAAI,GAAG,IAAI,GAAG,KAAK;CAC7C,OAAO;AACT;AAEA,SAAS,aAAa,QAA6B;CACjD,MAAM,KACJ,OAAO,YAGP;CACF,IAAI,CAAC,MAAM,QAAQ,EAAE,GAAG,OAAO,CAAC;CAChC,OAAO,GAAG,KAAK,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,EAAE,OAAO,OAAO;AAC9D;;;;;AAMA,SAAgB,cAAc,UAAkB,UAAwB;CACtE,MAAM,MAAM,cAAc,UAAU,QAAQ;CAC5C,IAAI,CAAC,WAAW,GAAG,GAAG;CACtB,KAAK,MAAM,OAAO,SAAS,UAAU,QAAQ,GAAG;EAC9C,IAAI,IAAI,WAAW,WAAW;EAC9B,MAAM,OAAO,SAAS,KAAK,KAAK,IAAI,MAAM,CAAC;EAC3C,IAAI,CAAC,MAAM;EACX,IAAI,WAAW,KAAK,GAAG,GAAG;EAC1B,MAAM,cAA4B;GAChC,MAAM;GACN,WAAW;GACX,QAAQ;GACR,QAAQ,cAAc,KAAK,IAAI;GAC/B,IAAI,KAAK,IAAI,IAAI;EACnB;EACA,iBAAiB,IAAI,aAAa,WAAW;EAE7C,MAAM,QAAQ,iBAA4B,IAAI,UAAU;EACxD,IAAI,OAAO;GACT,MAAM,SAAS;GACf,MAAM,4BAAW,IAAI,KAAK,GAAE,YAAY;GACxC,gBAAgB,IAAI,YAAY,KAAK;EACvC;EACA,UAAU,KAAK,KAAK,IAAI,MAAM,CAAC;CACjC;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"system.js","names":["parseYaml"],"sources":["../../../src/lib/system.ts"],"sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { parse as parseYaml } from \"yaml\";\nimport { kaizenSystemPath } from \"./paths.js\";\n\nexport type EvalStyle = \"ground-truth\" | \"llm-as-judge\" | \"hybrid\";\n\nexport interface SubgroupDef {\n name: string;\n field: string;\n}\n\nexport interface SystemFrontmatter {\n name: string;\n description?: string;\n run_eval: string;\n eval_version: number;\n dataset_version: string;\n eval_style?: EvalStyle;\n primary_metric: string;\n target?: number;\n kaizen_version?: string;\n subgroups?: SubgroupDef[];\n [key: string]: unknown;\n}\n\nexport interface SystemDef {\n id: string;\n path: string;\n frontmatter: SystemFrontmatter;\n body: string;\n}\n\nfunction systemPath(workspaceRoot: string, id: string): string {\n return kaizenSystemPath(workspaceRoot, id);\n}\n\nexport function loadSystem(workspaceRoot: string, id: string): SystemDef {\n const path = systemPath(workspaceRoot, id);\n if (!existsSync(path)) {\n throw new Error(\n `system \"${id}\" not found at ${path}. run \\`kaizen create system ${id}\\` to scaffold one.`,\n );\n }\n const text = readFileSync(path, \"utf-8\");\n const { frontmatter, body } = splitFrontmatter(text);\n if (!frontmatter) {\n throw new Error(`system ${id}: no YAML frontmatter found in ${path}`);\n }\n const fm = parseYaml(frontmatter) as Partial<SystemFrontmatter> | null;\n if (!fm || typeof fm !== \"object\") {\n throw new Error(`system ${id}: frontmatter is not a YAML mapping`);\n }\n const required = [\n \"name\",\n \"run_eval\",\n \"eval_version\",\n \"dataset_version\",\n \"primary_metric\",\n ] as const;\n for (const k of required) {\n if (fm[k] === undefined || fm[k] === null || fm[k] === \"\") {\n throw new Error(\n `system ${id}: frontmatter missing required field \"${k}\"`,\n );\n }\n }\n return {\n id,\n path,\n frontmatter: fm as SystemFrontmatter,\n body,\n };\n}\n\nexport function resolveEvalPath(\n workspaceRoot: string,\n system: SystemDef,\n): string {\n return resolve(workspaceRoot, system.frontmatter.run_eval);\n}\n\nfunction splitFrontmatter(text: string): {\n frontmatter: string | null;\n body: string;\n} {\n // Frontmatter starts on line 1 with ---, ends with --- on its own line.\n if (!text.startsWith(\"---\")) return { frontmatter: null, body: text };\n const lines = text.split(\"\\n\");\n // First line is \"---\". Find the next \"---\".\n let close = -1;\n for (let i = 1; i < lines.length; i++) {\n if (lines[i].trim() === \"---\") {\n close = i;\n break;\n }\n }\n if (close === -1) return { frontmatter: null, body: text };\n return {\n frontmatter: lines.slice(1, close).join(\"\\n\"),\n body: lines.slice(close + 1).join(\"\\n\"),\n };\n}\n"],"mappings":";;;;;;AAiCA,SAAS,WAAW,eAAuB,IAAoB;
|
|
1
|
+
{"version":3,"file":"system.js","names":["parseYaml"],"sources":["../../../src/lib/system.ts"],"sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { parse as parseYaml } from \"yaml\";\nimport { kaizenSystemPath } from \"./paths.js\";\n\nexport type EvalStyle = \"ground-truth\" | \"llm-as-judge\" | \"hybrid\";\n\nexport interface SubgroupDef {\n name: string;\n field: string;\n}\n\nexport interface SystemFrontmatter {\n name: string;\n description?: string;\n run_eval: string;\n eval_version: number;\n dataset_version: string;\n eval_style?: EvalStyle;\n primary_metric: string;\n target?: number;\n kaizen_version?: string;\n subgroups?: SubgroupDef[];\n [key: string]: unknown;\n}\n\nexport interface SystemDef {\n id: string;\n path: string;\n frontmatter: SystemFrontmatter;\n body: string;\n}\n\nfunction systemPath(workspaceRoot: string, id: string): string {\n return kaizenSystemPath(workspaceRoot, id);\n}\n\nexport function loadSystem(workspaceRoot: string, id: string): SystemDef {\n const path = systemPath(workspaceRoot, id);\n if (!existsSync(path)) {\n throw new Error(\n `system \"${id}\" not found at ${path}. run \\`kaizen create system ${id}\\` to scaffold one.`,\n );\n }\n const text = readFileSync(path, \"utf-8\");\n const { frontmatter, body } = splitFrontmatter(text);\n if (!frontmatter) {\n throw new Error(`system ${id}: no YAML frontmatter found in ${path}`);\n }\n const fm = parseYaml(frontmatter) as Partial<SystemFrontmatter> | null;\n if (!fm || typeof fm !== \"object\") {\n throw new Error(`system ${id}: frontmatter is not a YAML mapping`);\n }\n const required = [\n \"name\",\n \"run_eval\",\n \"eval_version\",\n \"dataset_version\",\n \"primary_metric\",\n ] as const;\n for (const k of required) {\n if (fm[k] === undefined || fm[k] === null || fm[k] === \"\") {\n throw new Error(\n `system ${id}: frontmatter missing required field \"${k}\"`,\n );\n }\n }\n return {\n id,\n path,\n frontmatter: fm as SystemFrontmatter,\n body,\n };\n}\n\nexport function resolveEvalPath(\n workspaceRoot: string,\n system: SystemDef,\n): string {\n return resolve(workspaceRoot, system.frontmatter.run_eval);\n}\n\nfunction splitFrontmatter(text: string): {\n frontmatter: string | null;\n body: string;\n} {\n // Frontmatter starts on line 1 with ---, ends with --- on its own line.\n if (!text.startsWith(\"---\")) return { frontmatter: null, body: text };\n const lines = text.split(\"\\n\");\n // First line is \"---\". Find the next \"---\".\n let close = -1;\n for (let i = 1; i < lines.length; i++) {\n if (lines[i].trim() === \"---\") {\n close = i;\n break;\n }\n }\n if (close === -1) return { frontmatter: null, body: text };\n return {\n frontmatter: lines.slice(1, close).join(\"\\n\"),\n body: lines.slice(close + 1).join(\"\\n\"),\n };\n}\n"],"mappings":";;;;;;AAiCA,SAAS,WAAW,eAAuB,IAAoB;CAC7D,OAAO,iBAAiB,eAAe,EAAE;AAC3C;AAEA,SAAgB,WAAW,eAAuB,IAAuB;CACvE,MAAM,OAAO,WAAW,eAAe,EAAE;CACzC,IAAI,CAAC,WAAW,IAAI,GAClB,MAAM,IAAI,MACR,WAAW,GAAG,iBAAiB,KAAK,+BAA+B,GAAG,oBACxE;CAGF,MAAM,EAAE,aAAa,SAAS,iBADjB,aAAa,MAAM,OACkB,CAAC;CACnD,IAAI,CAAC,aACH,MAAM,IAAI,MAAM,UAAU,GAAG,iCAAiC,MAAM;CAEtE,MAAM,KAAKA,MAAU,WAAW;CAChC,IAAI,CAAC,MAAM,OAAO,OAAO,UACvB,MAAM,IAAI,MAAM,UAAU,GAAG,oCAAoC;CASnE,KAAK,MAAM,KAAK;EANd;EACA;EACA;EACA;EACA;CAEqB,GACrB,IAAI,GAAG,OAAO,KAAA,KAAa,GAAG,OAAO,QAAQ,GAAG,OAAO,IACrD,MAAM,IAAI,MACR,UAAU,GAAG,wCAAwC,EAAE,EACzD;CAGJ,OAAO;EACL;EACA;EACA,aAAa;EACb;CACF;AACF;AAEA,SAAgB,gBACd,eACA,QACQ;CACR,OAAO,QAAQ,eAAe,OAAO,YAAY,QAAQ;AAC3D;AAEA,SAAS,iBAAiB,MAGxB;CAEA,IAAI,CAAC,KAAK,WAAW,KAAK,GAAG,OAAO;EAAE,aAAa;EAAM,MAAM;CAAK;CACpE,MAAM,QAAQ,KAAK,MAAM,IAAI;CAE7B,IAAI,QAAQ;CACZ,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAChC,IAAI,MAAM,GAAG,KAAK,MAAM,OAAO;EAC7B,QAAQ;EACR;CACF;CAEF,IAAI,UAAU,IAAI,OAAO;EAAE,aAAa;EAAM,MAAM;CAAK;CACzD,OAAO;EACL,aAAa,MAAM,MAAM,GAAG,KAAK,EAAE,KAAK,IAAI;EAC5C,MAAM,MAAM,MAAM,QAAQ,CAAC,EAAE,KAAK,IAAI;CACxC;AACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
._page_x8qc7_1{color:#fafafa;background:#0a0a0a;min-height:100%;font-family:Geist,ui-sans-serif,system-ui,-apple-system,sans-serif}._topBar_x8qc7_13{grid-template-columns:max-content max-content max-content minmax(0,1fr);align-items:center;gap:.9rem;padding:1rem 1.5rem;display:grid}._logoLink_x8qc7_21{justify-content:center;align-items:center;width:26px;height:26px;text-decoration:none;display:inline-flex}._topLogo_x8qc7_30{object-fit:contain;width:22px;height:22px;display:block}._systemSlot_x8qc7_37{min-width:0}._surfaceNav_x8qc7_41{align-items:center;gap:.25rem;min-width:0;display:flex}._surfaceLink_x8qc7_48{height:32px;color:var(--text-tertiary);white-space:nowrap;border-radius:0;justify-content:center;align-items:center;padding:0 .8rem;font-size:.85rem;font-weight:500;text-decoration:none;transition:background .15s,color .15s;display:inline-flex}._surfaceLink_x8qc7_48:hover{color:var(--text-secondary);background:#ffffff0d}._surfaceLinkActive_x8qc7_70{color:#fafafa;background:#ffffff14}._surfaceLinkDisabled_x8qc7_75{opacity:.45;pointer-events:none}._statusPill_x8qc7_80{min-height:22px;color:var(--text-secondary);white-space:nowrap;background:#ffffff0f;border:1px solid #ffffff14;border-radius:0;align-items:center;padding:0 .45rem;font-size:.68rem;font-weight:600;display:inline-flex}._content_x8qc7_94{padding:0 1.5rem 2rem}._surface_x8qc7_41{min-width:0}._surfaceBanner_x8qc7_102{box-sizing:border-box;background:#ffffff09;border:1px solid #ffffff14;border-radius:0;justify-content:space-between;align-items:flex-start;gap:1rem;width:100%;margin-bottom:1rem;padding:.8rem .9rem;display:flex}._surfaceBannerText_x8qc7_116{min-width:0}._surfaceBannerTitle_x8qc7_120{color:#fafafa;align-items:center;gap:.45rem;font-size:.9rem;font-weight:650;display:flex}._surfaceBannerCopy_x8qc7_129{color:var(--text-secondary);margin-top:.2rem;font-size:.78rem;line-height:1.45}._surfaceBannerCopy_x8qc7_129 code{color:#fafafa;background:#0000003d;border-radius:0;padding:.05rem .25rem}._sourceChip_x8qc7_143{color:#fafafa;vertical-align:middle;background:#ffffff0a;border:1px solid #ffffff1a;border-radius:0;justify-content:center;align-items:center;width:22px;height:22px;padding:0;line-height:1;display:inline-flex}._sourceChip_code_x8qc7_158{color:#fafafa}._sourceChip_langfuse_x8qc7_162,._sourceChip_linear_x8qc7_166{background:#ffffff0f}._sourceChip_local_x8qc7_170{color:#fafafa}._sourceLogo_x8qc7_174{object-fit:contain;width:15px;height:15px;display:block}._sourceSvgIcon_x8qc7_181{width:15px;height:15px;display:block}._provenanceLine_x8qc7_187{color:var(--text-tertiary);flex-wrap:wrap;align-items:center;gap:.4rem;margin-top:.45rem;font-size:.74rem;display:flex}._provenanceLine_x8qc7_187 code{color:#fafafa;background:#0000003d;border-radius:0;padding:.08rem .28rem}._inlineSourceValue_x8qc7_204{vertical-align:middle;white-space:nowrap;align-items:center;gap:.35rem;display:inline-flex}._syncStatus_x8qc7_212{flex-shrink:0;justify-content:flex-end;align-items:center;gap:.4rem;display:flex}._syncStatusLabel_x8qc7_220{color:var(--text-tertiary);white-space:nowrap;font-size:.74rem;font-weight:500}._iconButton_x8qc7_227{color:#fafafa;cursor:pointer;white-space:nowrap;background:#ffffff0a;border:1px solid #ffffff17;border-radius:0;justify-content:center;align-items:center;width:32px;height:32px;padding:0;font-family:inherit;font-size:1rem;line-height:1;display:inline-flex}._iconButton_x8qc7_227:hover:not(:disabled){background:#ffffff12;border-color:#ffffff26}._iconButton_x8qc7_227:disabled{color:var(--text-tertiary);cursor:default}._dataLayout_x8qc7_255{grid-template-columns:9.5rem minmax(0,1fr);align-items:start;gap:0;display:grid}._experimentsLayout_x8qc7_262{align-items:flex-start;min-width:0;display:flex}._dataNav_x8qc7_268{box-sizing:border-box;border-right:1px solid #ffffff14;flex-direction:column;align-self:stretch;gap:.25rem;min-height:calc(100vh - 8rem);padding:0 1rem 0 0;display:flex}._experimentNav_x8qc7_279{border-right:none;flex:none;min-width:220px;max-width:min(520px,45vw);padding:0;overflow:auto}._experimentNavItem_x8qc7_288{box-sizing:border-box;width:100%;display:flex}._sidebarResizeHandle_x8qc7_294{cursor:col-resize;flex:0 0 16px;align-self:stretch;min-height:calc(100vh - 8rem);position:relative}._sidebarResizeHandle_x8qc7_294:before{content:"";background:#ffffff14;width:1px;transition:background .12s;position:absolute;top:0;bottom:0;left:7px}._sidebarResizeHandle_x8qc7_294:hover:before{background:#ffffff38}._dataNavItem_x8qc7_317{width:fit-content;min-height:32px;color:var(--text-tertiary);cursor:pointer;text-align:left;background:0 0;border:0;border-radius:0;justify-content:flex-start;align-items:center;padding:0 .8rem;font-family:inherit;font-size:.85rem;font-weight:500;text-decoration:none;transition:background .15s,color .15s;display:inline-flex}._dataNavGroupItem_x8qc7_339{flex-direction:column;align-items:flex-start;gap:.12rem;width:100%;min-height:48px;padding:.4rem .65rem}._dataNavItemText_x8qc7_348,._dataNavItemMeta_x8qc7_349{text-overflow:ellipsis;white-space:nowrap;width:100%;min-width:0;display:block;overflow:hidden}._experimentNavItem_x8qc7_288 ._dataNavItemText_x8qc7_348,._experimentNavItem_x8qc7_288 ._dataNavItemMeta_x8qc7_349{text-overflow:clip;white-space:normal;overflow:visible}._dataNavItemText_x8qc7_348{color:inherit;line-height:1.2}._dataNavItemMeta_x8qc7_349{color:var(--text-tertiary);font-size:.7rem;line-height:1.2}._dataNavEmpty_x8qc7_376{color:var(--text-tertiary);padding:.5rem .65rem;font-size:.78rem}._experimentNavEmpty_x8qc7_382{box-sizing:border-box;flex-direction:column;gap:.25rem;width:100%;padding:.5rem .65rem;display:flex}._dataNavEmptyTitle_x8qc7_391{color:var(--text-secondary);font-size:.82rem;font-weight:500;line-height:1.25}._dataNavEmptyCopy_x8qc7_398{color:var(--text-tertiary);font-size:.74rem;line-height:1.4}._dataNavItem_x8qc7_317:hover{color:var(--text-secondary);background:#ffffff0d}._dataNavItem_x8qc7_317:focus{outline:none}._dataNavItemActive_x8qc7_413{color:#fafafa;background:#ffffff14}._dataLayout_x8qc7_255>._dataNav_x8qc7_268{width:100%;padding:0}._dataLayout_x8qc7_255>._dataNav_x8qc7_268 ._dataNavItem_x8qc7_317{box-sizing:border-box;width:100%;display:flex}._dataMain_x8qc7_429{flex:auto;min-width:0;padding:0 1.5rem 1.5rem}._surfaceToolbar_x8qc7_435{justify-content:space-between;align-items:center;gap:1rem;margin-bottom:1rem;display:flex}._tracesToolbarSearch_x8qc7_443{flex:auto;align-items:center;gap:.45rem;min-width:0;display:flex}._textInput_x8qc7_451._traceSearchInput_x8qc7_451{width:min(390px,44vw);height:28px;min-height:28px;padding:0 .6rem;font-size:.8rem;font-weight:500;line-height:1}._textInput_x8qc7_451._traceSearchInput_x8qc7_451::placeholder{color:#ffffff6b;font-weight:450}._secondaryButton_x8qc7_466._traceSearchButton_x8qc7_466{flex:0 0 28px;justify-content:center;align-items:center;width:28px;height:28px;padding:0;display:inline-flex}._traceDateRangeLabel_x8qc7_476{color:#fff9;white-space:nowrap;font-size:.75rem;font-weight:500}._textInput_x8qc7_451._traceDateInput_x8qc7_483{--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark;height:28px;min-height:28px;padding:0 .5rem;font-size:.75rem;font-weight:500;line-height:1}._searchIcon_x8qc7_493{background:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fafafa' stroke-width='2.25' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='6.5'/%3E%3Cpath d='m16 16 4.5 4.5'/%3E%3C/svg%3E") 50%/14px 14px no-repeat;width:14px;height:14px;display:block}._tracesToolbarRight_x8qc7_501{justify-content:flex-end;align-items:center;gap:.65rem;min-width:max-content;margin-left:auto;display:flex}._surfaceTitle_x8qc7_510{color:#fafafa;font-size:.95rem;font-weight:600}._surfaceSubtitle_x8qc7_516{color:var(--text-tertiary);margin-top:.15rem;font-size:.75rem}._inlineSelector_x8qc7_522{align-items:center;gap:.45rem;width:max-content;min-width:0;display:inline-flex}._inlineSelectorLabel_x8qc7_530{color:var(--text-tertiary);letter-spacing:.04em;text-transform:uppercase;white-space:nowrap;font-size:.72rem;font-weight:600}._filterBar_x8qc7_539{justify-content:flex-end;margin-bottom:1rem;display:flex}._select_x8qc7_545,._primaryButton_x8qc7_546,._secondaryButton_x8qc7_466,._dangerButton_x8qc7_548{color:#fafafa;background:#ffffff0a;border:1px solid #ffffff17;border-radius:0;height:32px;font-family:inherit;font-size:.8rem}._select_x8qc7_545{appearance:none;background:linear-gradient(45deg,#0000 50%,#ffffff94 50%) calc(100% - 14px) 13px/5px 5px no-repeat,linear-gradient(135deg,#ffffff94 50%,#0000 50%) calc(100% - 9px) 13px/5px 5px no-repeat,#ffffff0a;max-width:340px;padding:0 1.8rem 0 .5rem}._select_x8qc7_545:focus{background-color:#ffffff0f;border-color:#ffffff38;outline:none}._select_x8qc7_545 option{color:#fafafa;background:#111}._checkboxInput_x8qc7_582{appearance:none;cursor:pointer;vertical-align:middle;background:#ffffff0a;border:1px solid #ffffff3d;place-content:center;width:14px;height:14px;margin:0;display:inline-grid}._checkboxInput_x8qc7_582:before{content:"";opacity:0;border-bottom:1.8px solid #0a0a0a;border-left:1.8px solid #0a0a0a;width:7px;height:4px;transform:translateY(-1px)rotate(-45deg)}._checkboxInput_x8qc7_582:checked{background:#fafafa;border-color:#fafafa}._checkboxInput_x8qc7_582:checked:before{opacity:1}._checkboxInput_x8qc7_582:indeterminate{background:#fafafa;border-color:#fafafa}._checkboxInput_x8qc7_582:indeterminate:before{opacity:1;border-bottom:1.8px solid #0a0a0a;border-left:0;width:8px;height:0;transform:none}._checkboxInput_x8qc7_582:focus{border-color:#ffffff80;outline:none}._dropdown_x8qc7_633{width:100%;max-width:340px;position:relative}._dropdownButton_x8qc7_639{color:#fafafa;cursor:pointer;text-align:left;background:#ffffff0a;border:1px solid #ffffff17;justify-content:space-between;align-items:center;gap:.65rem;width:100%;height:32px;padding:0 .6rem;font-family:inherit;font-size:.8rem;display:inline-flex}._dropdownButton_x8qc7_639:hover:not(:disabled),._dropdownButton_x8qc7_639[aria-expanded=true]{background:#ffffff0f;border-color:#ffffff2e}._dropdownButton_x8qc7_639:focus{border-color:#ffffff38;outline:none}._dropdownButton_x8qc7_639:disabled{color:var(--text-tertiary);cursor:default}._dropdownValue_x8qc7_672{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}._dropdownChevron_x8qc7_679{border-bottom:1px solid #ffffff9e;border-right:1px solid #ffffff9e;flex:0 0 7px;width:7px;height:7px;transform:translateY(-2px)rotate(45deg)}._dropdownMenu_x8qc7_688{z-index:1100;background:#111;border:1px solid #ffffff1f;max-height:220px;position:absolute;top:calc(100% + .25rem);left:0;right:0;overflow:auto;box-shadow:0 10px 24px #00000085}._dropdownOption_x8qc7_701{width:100%;min-height:32px;color:var(--text-secondary);cursor:pointer;text-align:left;background:0 0;border:0;border-bottom:1px solid #ffffff0f;padding:.45rem .6rem;font-family:inherit;font-size:.8rem;display:block}._dropdownOption_x8qc7_701:last-child{border-bottom:0}._dropdownOption_x8qc7_701:hover,._dropdownOptionSelected_x8qc7_721{color:#fafafa;background:#ffffff14}._dropdownOption_x8qc7_701:focus{color:#fafafa;background:#ffffff14;outline:none}._primaryButton_x8qc7_546{cursor:pointer;color:#0a0a0a;background:#fafafa;border-color:#fafafa;padding:0 .85rem;font-weight:600}._secondaryButton_x8qc7_466{cursor:pointer;padding:0 .75rem}._dangerButton_x8qc7_548{cursor:pointer;color:#ffb3a6;background:#e8553d14;border-color:#e8553d38;padding:0 .75rem}._primaryButton_x8qc7_546:hover:not(:disabled){background:var(--text-secondary);border-color:var(--text-secondary)}._secondaryButton_x8qc7_466:hover:not(:disabled){background:#ffffff12;border-color:#ffffff26}._dangerButton_x8qc7_548:hover:not(:disabled){background:#e8553d21;border-color:#e8553d57}._primaryButton_x8qc7_546:disabled,._secondaryButton_x8qc7_466:disabled,._dangerButton_x8qc7_548:disabled{color:var(--text-tertiary);cursor:default}._primaryButton_x8qc7_546:disabled{background:#ffffff14;border-color:#ffffff17}._splitSurface_x8qc7_781{grid-template-columns:minmax(240px,340px) minmax(0,1fr);gap:1rem;min-height:560px;display:grid}._listPanel_x8qc7_788,._listPanelEmpty_x8qc7_789,._detailPanel_x8qc7_790,._errorPanel_x8qc7_791,._loadingPanel_x8qc7_792,._emptyPanel_x8qc7_793{background:#ffffff08;border:1px solid #ffffff14;border-radius:0}._listPanel_x8qc7_788{max-height:calc(100vh - 280px);overflow:auto}._listPanelEmpty_x8qc7_789,._loadingPanel_x8qc7_792,._emptyPanel_x8qc7_793{min-height:260px;color:var(--text-tertiary);text-align:center;justify-content:center;align-items:center;padding:2rem;font-size:.86rem;display:flex}._listRow_x8qc7_817{width:100%;color:inherit;text-align:left;white-space:normal;cursor:pointer;background:0 0;border:0;border-bottom:1px solid #ffffff0d;flex-direction:column;align-items:stretch;gap:.2rem;padding:.75rem;font-family:inherit;display:flex}._listRow_x8qc7_817:hover{background:#ffffff0a}._listRowSelected_x8qc7_838{background:#5b8def1a;box-shadow:inset 2px 0 #5b8def}._listRowTitle_x8qc7_843{color:#fafafa;overflow-wrap:anywhere;text-overflow:clip;white-space:normal;min-width:0;font-size:.82rem;font-weight:500;line-height:1.28;display:block;overflow:visible}._listRowMeta_x8qc7_856{min-width:0;color:var(--text-tertiary);text-overflow:ellipsis;white-space:nowrap;font-size:.72rem;overflow:hidden}._listRowLinked_x8qc7_865{color:#9ebcffdb;text-overflow:ellipsis;white-space:nowrap;min-width:0;font-size:.7rem;overflow:hidden}._detailPanel_x8qc7_790{min-width:0;max-height:calc(100vh - 280px);padding:1rem;overflow:auto}._detailHeader_x8qc7_881{justify-content:space-between;align-items:flex-start;gap:1rem;margin-bottom:1rem;display:flex}._detailHeaderMain_x8qc7_889{flex:auto;min-width:0}._detailTitleRow_x8qc7_894{flex-wrap:wrap;align-items:center;gap:.45rem;min-width:0;display:flex}._detailHeaderAction_x8qc7_902{align-self:flex-start}._detailTitle_x8qc7_894{color:#fafafa;overflow-wrap:anywhere;margin:0;font-size:1rem;font-weight:600;line-height:1.35}._detailMeta_x8qc7_915,._mutedText_x8qc7_916{color:var(--text-tertiary);overflow-wrap:anywhere;margin-top:.2rem;font-size:.74rem}._detailLink_x8qc7_923{color:#5b8def;font-size:.78rem;text-decoration:none}._detailLink_x8qc7_923:hover{text-decoration:underline}._detailGrid_x8qc7_933{grid-template-columns:repeat(2,minmax(0,1fr));gap:.75rem;display:grid}._jsonBlock_x8qc7_939{min-width:0;margin-bottom:.75rem}._jsonTitle_x8qc7_944,._sectionTitle_x8qc7_945{color:var(--text-secondary);text-transform:uppercase;letter-spacing:.04em;margin-bottom:.35rem;font-size:.72rem;font-weight:600}._jsonPre_x8qc7_954{max-height:320px;color:var(--text-secondary);white-space:pre-wrap;overflow-wrap:anywhere;background:#00000047;border-radius:0;margin:0;padding:.75rem;font-size:.75rem;line-height:1.45;overflow:auto}._traceSection_x8qc7_968{margin-top:1rem}._traceHeader_x8qc7_972{align-items:baseline;gap:.75rem;margin-bottom:.6rem;display:flex}._traceName_x8qc7_979{color:#fafafa;overflow-wrap:anywhere;font-size:.9rem;font-weight:600}._tagRow_x8qc7_986{flex-wrap:wrap;gap:.35rem;margin:.75rem 0;display:flex}._tagPill_x8qc7_993{color:#9ebcff;background:#5b8def1f;border:1px solid #5b8def38;border-radius:0;align-items:center;min-height:22px;padding:0 .45rem;font-size:.7rem;font-weight:500;display:inline-flex}._labelPill_x8qc7_1006{white-space:nowrap;border-radius:0;align-items:center;min-height:22px;padding:0 .45rem;font-size:.7rem;font-weight:600;display:inline-flex}._labelPillLabeled_x8qc7_1017{color:#b8f5df;background:#00d4aa1a;border:1px solid #00d4aa47}._labelPillUnlabeled_x8qc7_1023{color:#ffffff94;background:#ffffff0e;border:1px solid #ffffff1c}._itemStepper_x8qc7_1029{flex:none;justify-content:flex-end;align-items:center;gap:.4rem;display:flex}._itemStepper_x8qc7_1029 ._secondaryButton_x8qc7_466{width:30px;min-width:30px;height:28px;padding:0;line-height:1}._itemStepperLabel_x8qc7_1045{min-width:52px;color:var(--text-tertiary);text-align:right;white-space:nowrap;font-size:.74rem}._errorPanel_x8qc7_791{color:#ffb3a6;background:#e8553d1a;border-color:#e8553d4d;margin-bottom:1rem;padding:.75rem;font-size:.82rem}._successPanel_x8qc7_1062{color:#b8f5df;background:#00d4aa14;border:1px solid #00d4aa38;border-radius:0;margin-bottom:1rem;padding:.75rem;font-size:.82rem}._evalDefinitionGrid_x8qc7_1072{grid-template-columns:repeat(4,minmax(0,1fr));gap:.75rem;display:grid}._evalDefinitionCell_x8qc7_1078{min-width:0}._evalDefinitionCode_x8qc7_1082{width:fit-content;max-width:100%;color:var(--text-tertiary);overflow-wrap:anywhere;background:#0000003d;margin-top:.2rem;padding:.1rem .28rem;font-size:.72rem;display:block}._evalHistorySection_x8qc7_1094{margin-top:1rem}._evalSectionHeader_x8qc7_1098{justify-content:space-between;align-items:flex-start;gap:1rem;margin-bottom:.75rem;display:flex}._evalSummaryTable_x8qc7_1106{background:#ffffff08;border:1px solid #ffffff14}._evalSummaryHeader_x8qc7_1111,._evalSummaryRow_x8qc7_1112{grid-template-columns:minmax(180px,1.35fr) minmax(180px,1.35fr) 80px 80px 160px;align-items:center;gap:.75rem;display:grid}._evalSummaryHeader_x8qc7_1111{color:var(--text-tertiary);letter-spacing:.04em;text-transform:uppercase;border-bottom:1px solid #ffffff14;padding:.55rem .75rem;font-size:.7rem;font-weight:600}._evalSummaryRow_x8qc7_1112{color:var(--text-secondary);border-bottom:1px solid #ffffff0d;padding:.65rem .75rem;font-size:.78rem}._evalSummaryRow_x8qc7_1112:last-child{border-bottom:0}._evalSummaryPrimary_x8qc7_1142,._evalSummaryMeta_x8qc7_1143{text-overflow:ellipsis;white-space:nowrap;min-width:0;display:block;overflow:hidden}._evalSummaryPrimary_x8qc7_1142{color:#fafafa;font-weight:500}._evalSummaryMeta_x8qc7_1143{color:var(--text-tertiary);margin-top:.12rem;font-size:.7rem}._setupBanner_x8qc7_1162{background:#f5a62314;border:1px solid #f5a62357;border-radius:0;margin-bottom:1rem;padding:.85rem}._setupTitle_x8qc7_1170{color:#fafafa;font-size:.88rem;font-weight:600}._setupCopy_x8qc7_1176{color:var(--text-secondary);margin-top:.2rem;font-size:.8rem;line-height:1.5}._setupHeader_x8qc7_1183{justify-content:space-between;align-items:flex-start;gap:1rem;display:flex}._setupState_x8qc7_1190{color:#f5c77b;white-space:nowrap;background:#f5a6231a;border:1px solid #f5a6234d;border-radius:0;align-items:center;min-height:22px;padding:0 .45rem;font-size:.68rem;font-weight:600;display:inline-flex}._setupGrid_x8qc7_1204{grid-template-columns:repeat(3,minmax(0,1fr));gap:.75rem;margin-top:.8rem;display:grid}._setupBlock_x8qc7_1211{min-width:0}._setupBlockTitle_x8qc7_1215{color:var(--text-tertiary);text-transform:uppercase;letter-spacing:.04em;margin-bottom:.35rem;font-size:.68rem;font-weight:600;display:block}._setupCode_x8qc7_1225{color:#fafafa;overflow-wrap:anywhere;background:#00000042;border-radius:0;width:fit-content;max-width:100%;margin-top:.25rem;padding:.18rem .38rem;font-size:.72rem;display:block}._setupLookup_x8qc7_1238,._setupDetail_x8qc7_1239{color:var(--text-tertiary);overflow-wrap:anywhere;margin-top:.75rem;font-size:.75rem;line-height:1.5}._setupLookupLabel_x8qc7_1247{color:var(--text-secondary);margin-right:.35rem;font-weight:600}._ideaMetaGrid_x8qc7_1253{grid-template-columns:repeat(4,minmax(0,1fr));gap:.75rem;margin-bottom:.75rem;display:grid}._metaCell_x8qc7_1260{min-width:0}._metaLabel_x8qc7_1264{color:var(--text-tertiary);font-size:.7rem;display:block}._metaValue_x8qc7_1270{color:var(--text-secondary);text-overflow:ellipsis;white-space:nowrap;margin-top:.1rem;font-size:.78rem;display:block;overflow:hidden}._descriptionBlock_x8qc7_1280{white-space:pre-wrap;overflow-wrap:anywhere;color:var(--text-secondary);font-size:.84rem;line-height:1.55}._linkedExperimentsSection_x8qc7_1288{margin-bottom:1rem}._linkedExperimentsList_x8qc7_1292{gap:.5rem;display:grid}._linkedExperimentsEmpty_x8qc7_1297{color:var(--text-tertiary);background:#ffffff06;border:1px solid #ffffff14;padding:.65rem .75rem;font-size:.78rem}._linkedExperimentRow_x8qc7_1305{background:#ffffff06;border:1px solid #ffffff14;grid-template-columns:minmax(0,1fr) max-content;align-items:center;gap:.75rem;padding:.65rem .75rem;display:grid}._linkedExperimentMain_x8qc7_1315,._linkedExperimentStats_x8qc7_1316{min-width:0}._linkedExperimentTitle_x8qc7_1320{color:#fafafa;text-overflow:ellipsis;white-space:nowrap;min-width:0;font-size:.8rem;font-weight:600;display:block;overflow:hidden}._linkedExperimentStats_x8qc7_1316{justify-content:flex-end;align-items:center;gap:.45rem;display:inline-flex}._linkedExperimentScore_x8qc7_1338{color:#fafafa;white-space:nowrap;font-size:.8rem;font-weight:600}._linkedExperimentMeta_x8qc7_1345{min-width:0;color:var(--text-tertiary);text-overflow:ellipsis;white-space:nowrap;font-size:.7rem;display:block;overflow:hidden}._formRow_x8qc7_1355{flex-direction:column;gap:.35rem;margin-bottom:.75rem;display:flex}._formLabel_x8qc7_1362{color:var(--text-tertiary);text-transform:uppercase;letter-spacing:.04em;font-size:.72rem;font-weight:600}._textInput_x8qc7_451{color:#fafafa;background:#00000042;border:1px solid #ffffff1a;border-radius:0;min-height:34px;padding:0 .65rem;font-family:inherit;font-size:.84rem}._textArea_x8qc7_1381,._textAreaLarge_x8qc7_1382{resize:vertical;color:#fafafa;background:#00000042;border:1px solid #ffffff1a;border-radius:0;min-height:96px;padding:.6rem .65rem;font-family:inherit;font-size:.84rem;line-height:1.45}._textAreaLarge_x8qc7_1382{min-height:180px;font-family:Geist Mono,ui-monospace,monospace;font-size:.78rem}._textInput_x8qc7_451::placeholder,._textArea_x8qc7_1381::placeholder,._textAreaLarge_x8qc7_1382::placeholder{color:var(--text-tertiary)}._actionRow_x8qc7_1407{flex-wrap:wrap;justify-content:flex-end;gap:.5rem;display:flex}._actionFooter_x8qc7_1414{border-top:1px solid #ffffff14;justify-content:space-between;align-items:center;gap:1rem;margin:1rem 0;padding-top:.75rem;display:flex}._emptyState_x8qc7_1424{text-align:center;flex-direction:column;justify-content:center;align-items:center;gap:.9rem;min-height:560px;display:flex}._emptyLogo_x8qc7_1434{opacity:.85;width:220px;height:auto}._emptyTitle_x8qc7_1440{color:#fafafa;margin:0;font-size:1.45rem;font-weight:600}._emptyCopy_x8qc7_1447,._emptyMeta_x8qc7_1448,._emptyPanelCopy_x8qc7_1449{color:var(--text-tertiary);font-size:.86rem;line-height:1.5}._emptyPanel_x8qc7_793{flex-direction:column;gap:.35rem}._experimentEmptyPanel_x8qc7_1460{min-height:360px}._experimentEmptyPanel_x8qc7_1460 ._emptyPanelCopy_x8qc7_1449{max-width:420px}._experimentDetailSurface_x8qc7_1468{flex-direction:column;min-width:0;display:flex}._experimentDetailSummary_x8qc7_1474{background:#ffffff06;border:1px solid #ffffff14;margin-bottom:.8rem;padding:.85rem 1rem}._experimentDetailTitleRow_x8qc7_1481{justify-content:space-between;align-items:center;gap:1rem;display:flex}._experimentDetailTitleGroup_x8qc7_1488{flex-wrap:nowrap;flex:auto;align-items:center;gap:.45rem;min-width:0;display:flex}._experimentDetailTitle_x8qc7_1481{color:#fafafa;text-overflow:ellipsis;white-space:nowrap;margin:0;font-size:1rem;font-weight:600;line-height:1.25;overflow:hidden}._experimentDetailTimeRow_x8qc7_1508{color:var(--text-tertiary);white-space:nowrap;justify-content:flex-end;gap:.45rem;font-size:.68rem;line-height:1.35;display:flex}._experimentDetailTimeSeparator_x8qc7_1518{color:#ffffff38}._experimentMetricStrip_x8qc7_1522{border-top:1px solid #ffffff0f;grid-template-columns:repeat(auto-fit,minmax(118px,1fr));gap:0;margin-top:.75rem;padding-top:.75rem;display:grid}._experimentMetricItem_x8qc7_1531{border-right:1px solid #ffffff0f;grid-template-columns:minmax(0,auto) auto;align-items:baseline;gap:.15rem .45rem;min-width:0;padding-right:.75rem;display:grid}._experimentMetricItem_x8qc7_1531:last-child{border-right:0}._experimentMetricItemPrimary_x8qc7_1546 ._experimentMetricValue_x8qc7_1546{color:#00d4aa}._experimentMetricLabel_x8qc7_1550{color:var(--text-tertiary);font-size:.72rem;font-weight:500}._experimentMetricValue_x8qc7_1546{color:#fafafa;font-variant-numeric:tabular-nums;font-size:.95rem;font-weight:600}._emptyPanelTitle_x8qc7_1563{color:#fafafa;font-size:.95rem;font-weight:600}._runTracesPanel_x8qc7_1571{background:0 0;border:0;flex-direction:column;width:100%;min-width:0;display:flex;overflow:visible}._runTracesPanelHeader_x8qc7_1581{justify-content:space-between;align-items:flex-start;padding:0 0 .75rem;display:flex}._runTracesPanelTitle_x8qc7_1588{color:#fff;margin:0;font-size:1.1rem;font-weight:500}._runTracesDetail_x8qc7_1595{flex:1;padding:1rem 1.5rem;overflow-y:auto}._runTracesTableWrap_x8qc7_1601{background:#ffffff06;border:1px solid #ffffff14;flex:1;padding:0 0 1rem;overflow-y:auto}._datasetsTableWrap_x8qc7_1609{padding-bottom:1.25rem;overflow:visible}._runTracesTable_x8qc7_1601{border-collapse:collapse;width:100%;font-family:Geist,ui-sans-serif,system-ui,sans-serif;font-size:.8rem}._runTracesTable_x8qc7_1601 th{z-index:1;text-align:left;letter-spacing:0;color:#ffffff7a;-webkit-user-select:none;user-select:none;background:#101010;border-bottom:1px solid #ffffff14;padding:.6rem .75rem;font-size:.72rem;font-weight:600;position:sticky;top:0}._runTracesSortButton_x8qc7_1636{max-width:100%;color:inherit;cursor:pointer;font:inherit;text-align:left;background:0 0;border:0;align-items:center;gap:.35rem;padding:0;transition:color .15s;display:inline-flex}._runTracesSortButton_x8qc7_1636:hover{color:var(--text-secondary)}._runTracesSortButtonActive_x8qc7_1655{color:#ffffffe6}._runTracesSortIcon_x8qc7_1659{color:inherit;opacity:.76;font-size:.62rem;line-height:1}._runTracesTable_x8qc7_1601 td{color:#ffffffc7;border-bottom:1px solid #ffffff0a;padding:.55rem .75rem}._runTracesTableRowClickable_x8qc7_1672{cursor:pointer;transition:background-color .15s}._runTracesTableRowClickable_x8qc7_1672:hover{background:#ffffff0a}._datasetRowMenuOpen_x8qc7_1681{z-index:20;position:relative}._runTracesTableId_x8qc7_1686{text-overflow:ellipsis;white-space:nowrap;max-width:200px;font-family:Geist Mono,ui-monospace,monospace;font-size:.75rem;overflow:hidden}._datasetActionsCell_x8qc7_1695{width:40px;position:relative;overflow:visible}._datasetActionsCellOpen_x8qc7_1701{z-index:30}._datasetMenuAnchor_x8qc7_1705{z-index:1;justify-content:flex-end;width:100%;display:inline-flex;position:relative}._datasetActionsCellOpen_x8qc7_1701 ._datasetMenuAnchor_x8qc7_1705{z-index:40}._backButton_x8qc7_1717{color:var(--text-tertiary);cursor:pointer;background:0 0;border:0;border-radius:0;align-self:flex-start;align-items:center;gap:.25rem;margin-bottom:.65rem;padding:0;font-family:inherit;font-size:.72rem;font-weight:500;line-height:1.2;transition:color .15s;display:inline-flex}._backButton_x8qc7_1717:hover{color:var(--text-secondary)}._tagPillRemove_x8qc7_1740{color:#ffffff80;cursor:pointer;background:0 0;border:none;margin-left:.35rem;padding:0;font-size:.75rem;line-height:1}._tagPillRemove_x8qc7_1740:hover{color:#fff}._dataFieldLabel_x8qc7_1755{color:#ffffff80;margin-bottom:.35rem;font-size:.8rem}._membershipPanel_x8qc7_1761{background:#ffffff06;border:1px solid #ffffff14;grid-template-columns:minmax(170px,max-content) minmax(0,1fr);align-items:center;gap:.75rem;margin:0 0 .65rem;padding:.65rem .75rem;display:grid}._membershipPanelWithAction_x8qc7_1772{grid-template-columns:minmax(170px,max-content) minmax(0,1fr) max-content}._traceDatasetControls_x8qc7_1776{gap:.5rem;margin:0 0 .65rem;display:grid}._traceDatasetControls_x8qc7_1776 ._membershipPanel_x8qc7_1761{margin-bottom:0}._membershipHeader_x8qc7_1786{justify-content:space-between;align-items:center;gap:.75rem;min-width:0;display:flex}._membershipTitle_x8qc7_1794{color:#fafafa;font-size:.82rem;font-weight:600}._membershipMeta_x8qc7_1800{color:var(--text-tertiary);margin-top:.12rem;font-size:.7rem}._membershipContent_x8qc7_1806{min-width:0}._membershipList_x8qc7_1810{flex-wrap:wrap;gap:.4rem;display:flex}._membershipAction_x8qc7_1816{justify-content:flex-end;display:flex}._membershipActions_x8qc7_1821{flex-wrap:wrap;justify-content:flex-end;gap:.5rem;display:flex}._membershipAction_x8qc7_1816 ._primaryButton_x8qc7_546,._membershipAction_x8qc7_1816 ._secondaryButton_x8qc7_466{align-items:center;height:28px;padding:0 .65rem;font-size:.74rem;text-decoration:none;display:inline-flex}._membershipPill_x8qc7_1838{min-width:0;max-width:100%;min-height:24px;color:var(--text-secondary);background:#ffffff0a;border:1px solid #ffffff1a;align-items:center;gap:.3rem;padding:0 .35rem;font-size:.72rem;font-weight:600;transition:background .15s,border-color .15s,color .15s;display:inline-flex}._membershipPill_x8qc7_1838:hover,._membershipPill_x8qc7_1838:focus-within{color:#fafafa;background:#ffffff12;border-color:#ffffff29}._membershipPillText_x8qc7_1864{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}._membershipPillLink_x8qc7_1871{min-width:0;color:inherit;text-overflow:ellipsis;white-space:nowrap;align-items:center;text-decoration:none;display:inline-flex;overflow:hidden}._membershipPillLink_x8qc7_1871:hover{color:inherit;text-decoration:none}._membershipPillLink_x8qc7_1871:focus{outline:none}._membershipRemoveButton_x8qc7_1891{color:#ffffff8f;cursor:pointer;background:0 0;border:0;justify-content:center;align-items:center;width:16px;height:16px;padding:0;font-family:inherit;font-size:.9rem;line-height:1;display:inline-flex}._membershipRemoveButton_x8qc7_1891:hover:not(:disabled){color:#fafafa;background:#ffffff0f}._membershipRemoveButton_x8qc7_1891:disabled{cursor:default;opacity:.45}._membershipEmpty_x8qc7_1917{color:var(--text-tertiary);white-space:nowrap;font-size:.76rem}@media (width<=760px){._membershipPanel_x8qc7_1761,._membershipPanelWithAction_x8qc7_1772{grid-template-columns:1fr}._membershipAction_x8qc7_1816{justify-content:flex-start}._membershipEmpty_x8qc7_1917{white-space:normal}}._modalOverlay_x8qc7_1938{z-index:1000;background:#0009;justify-content:center;align-items:center;display:flex;position:fixed;inset:0}._modalContent_x8qc7_1948{background:#1a1a1a;border:1px solid #ffffff1f;border-radius:0;min-width:360px;max-width:480px;padding:1.5rem;box-shadow:0 8px 32px #0009}._modalTitle_x8qc7_1958{margin:0 0 1rem;font-size:1rem;font-weight:600}._modalMessage_x8qc7_1964{color:#fff9;margin:0 0 1rem;font-size:.85rem;line-height:1.4}._modalActions_x8qc7_1971{justify-content:flex-end;gap:.5rem;margin-top:1rem;display:flex}._contextMenu_x8qc7_1978{z-index:1000;pointer-events:auto;background:#1a1a1a;border:1px solid #ffffff1f;border-radius:0;min-width:120px;padding:.25rem 0;position:absolute;top:100%;right:0;box-shadow:0 4px 12px #0006}._contextMenuAbove_x8qc7_1992{top:auto;bottom:calc(100% + .25rem)}._contextMenuItem_x8qc7_1997{text-align:left;color:#ffffffd9;cursor:pointer;background:0 0;border:none;width:100%;padding:.5rem .75rem;font-size:.8rem;display:block}._contextMenuItem_x8qc7_1997:hover{background:#ffffff0f}._contextMenuItemDanger_x8qc7_2013{color:#ef4444}._paginationBar_x8qc7_2017{justify-content:center;align-items:center;gap:.35rem;padding:.5rem;display:flex}._paginationBarToolbar_x8qc7_2025{justify-content:flex-end;padding:0}._paginationIconButton_x8qc7_2030{flex:0 0 28px;width:28px;height:28px;font-size:.78rem}._paginationLabel_x8qc7_2037{color:#fff9;white-space:nowrap;padding:.25rem .45rem;font-size:.74rem}@media (width<=900px){._topBar_x8qc7_13{grid-template-columns:minmax(0,1fr);align-items:stretch}._surfaceNav_x8qc7_41{overflow-x:auto}._dataNav_x8qc7_268{border-bottom:1px solid #ffffff14;border-right:0;flex-direction:row;align-self:auto;width:100%;min-height:0;padding:0 0 .75rem;overflow-x:auto}._dataLayout_x8qc7_255>._dataNav_x8qc7_268 ._dataNavItem_x8qc7_317{flex:none;width:auto}._dataMain_x8qc7_429{padding:0}._experimentNav_x8qc7_279{min-width:0;max-width:none;width:100%!important}._experimentsLayout_x8qc7_262{flex-direction:column}._experimentsMain_x8qc7_2084{width:100%;margin-left:0}._sidebarResizeHandle_x8qc7_294{display:none}._surfaceToolbar_x8qc7_435,._surfaceBanner_x8qc7_102,._detailHeader_x8qc7_881,._traceHeader_x8qc7_972,._setupHeader_x8qc7_1183,._actionFooter_x8qc7_1414{flex-direction:column;align-items:stretch}._itemStepper_x8qc7_1029{justify-content:flex-start;margin-left:0}._itemStepperLabel_x8qc7_1045{text-align:left}._tracesToolbarSearch_x8qc7_443,._tracesToolbarRight_x8qc7_501{flex-wrap:wrap;justify-content:flex-start;min-width:0;margin-left:0}._textInput_x8qc7_451._traceSearchInput_x8qc7_451{width:min(100%,240px)}._syncStatus_x8qc7_212{justify-content:flex-start}._splitSurface_x8qc7_781,._dataLayout_x8qc7_255,._linkedExperimentRow_x8qc7_1305,._detailGrid_x8qc7_933,._evalDefinitionGrid_x8qc7_1072,._evalSummaryHeader_x8qc7_1111,._evalSummaryRow_x8qc7_1112,._ideaMetaGrid_x8qc7_1253,._setupGrid_x8qc7_1204{grid-template-columns:1fr}._listPanel_x8qc7_788,._detailPanel_x8qc7_790{max-height:none}._runTracesTableWrap_x8qc7_1601,._datasetsTableWrap_x8qc7_1609{overflow-x:auto}}._wrapper_18moo_1{align-items:center;gap:.45rem;width:max-content;min-width:0;display:inline-flex}._label_18moo_9{color:var(--text-tertiary,#666);letter-spacing:.04em;text-transform:uppercase;white-space:nowrap;font-size:.72rem;font-weight:600}._dropdown_18moo_18{width:clamp(144px,18vw,280px)}._layout_12m7d_3{background:#0a0a0a;flex:1;min-height:100%;display:flex}._heroLogo_12m7d_10{opacity:.85;width:240px;height:auto}._headerLogo_12m7d_18{object-fit:contain;border-radius:0;flex-shrink:0;width:18px;height:18px}._container_12m7d_26{color:#fafafa;box-sizing:border-box;background:#0a0a0a;flex:1;min-width:0;min-height:100%;margin:0;padding:2rem;font-family:Geist,ui-sans-serif,system-ui,-apple-system,sans-serif;overflow-x:hidden}._headerRow_12m7d_44{border-bottom:1px solid #ffffff0f;justify-content:space-between;align-items:center;gap:.75rem;margin-bottom:.5rem;padding:.6rem 0;display:flex}._title_12m7d_54{color:#fff;white-space:nowrap;flex-shrink:0;margin:0;font-size:1rem;font-weight:500}._connectedBadge_12m7d_65{text-transform:uppercase;letter-spacing:1px;color:#00d4aa;background:#00d4aa1a;border:1px solid #00d4aa66;padding:.2rem .6rem;font-size:.65rem;font-weight:500}._disconnectedBadge_12m7d_76{text-transform:uppercase;letter-spacing:1px;color:#f5a623;background:#f5a6231a;border:1px solid #f5a62366;padding:.2rem .6rem;font-size:.65rem;font-weight:500}._systemTabs_12m7d_89{border-bottom:1px solid #ffffff0f;gap:.25rem;margin-bottom:.5rem;padding-bottom:0;display:flex;overflow-x:auto}._systemTab_12m7d_89{color:var(--text-tertiary);cursor:pointer;white-space:nowrap;background:0 0;border:none;border-bottom:2px solid #0000;align-items:center;gap:.5rem;padding:.6rem 1rem;font-family:inherit;font-size:.85rem;font-weight:400;transition:color .15s,border-color .15s;display:flex}._systemTab_12m7d_89:hover{color:var(--text-secondary)}._systemTabActive_12m7d_121{color:#fff;border-bottom-color:#00d4aa}._systemTabName_12m7d_126{font-weight:400}._systemTabStatus_12m7d_130{text-transform:uppercase;letter-spacing:.5px;padding:.1rem .4rem;font-size:.6rem;font-weight:500}._systemStatus_in_progress_12m7d_138{color:#00d4aa;background:#00d4aa1a;border:1px solid #00d4aa4d}._systemStatus_completed_12m7d_144{color:#5b8def;background:#5b8def1a;border:1px solid #5b8def4d}._systemStatus_not_started_12m7d_150{color:var(--text-tertiary);background:#ffffff0a;border:1px solid #ffffff14}._subtitle_12m7d_156{color:var(--text-tertiary);margin-top:.15rem;font-size:.75rem;font-weight:400;line-height:1.4}._targetBadge_12m7d_164{color:var(--text-tertiary);white-space:nowrap;background:#ffffff0d;border:1px solid #ffffff14;border-radius:0;flex-shrink:0;padding:.1rem .4rem;font-size:.65rem}._grid_12m7d_177{grid-template-columns:repeat(3,1fr);gap:1.25rem;margin-bottom:3rem;display:grid}._card_12m7d_184{background:#ffffff08;border:1px solid #ffffff14;min-width:0;padding:1.5rem;transition:border-color .4s,box-shadow .4s;overflow:hidden}._card_12m7d_184:hover{border-color:#ffffff26}@keyframes _cardGlow_12m7d_1{0%{border-color:#00d4aacc;box-shadow:0 0 20px #00d4aa26,inset 0 0 20px #00d4aa08}to{box-shadow:none;border-color:#ffffff14}}@keyframes _badgePop_12m7d_1{0%{filter:brightness(1.8);transform:scale(1.3)}40%{transform:scale(.95)}to{filter:brightness();transform:scale(1)}}@keyframes _textHighlight_12m7d_1{0%{color:#00d4aa}to{color:var(--text-secondary)}}@keyframes _slideInFade_12m7d_1{0%{opacity:0;background:#00d4aa1f;transform:translateY(-8px)}40%{opacity:1;transform:translateY(0)}to{background:0 0}}@keyframes _diagramPulse_12m7d_1{0%{background:#00d4aa0f;border-color:#00d4aa80}to{background:#ffffff0a;border-color:#ffffff0f}}._cardFlash_12m7d_263{animation:1.2s ease-out forwards _cardGlow_12m7d_1}._badgeFlash_12m7d_267{animation:.5s cubic-bezier(.34,1.56,.64,1) forwards _badgePop_12m7d_1}._textFlash_12m7d_271{animation:1.2s ease-out forwards _textHighlight_12m7d_1}._rowSlideIn_12m7d_275{animation:.8s ease-out forwards _slideInFade_12m7d_1}._diagramFlash_12m7d_279{animation:1.2s ease-out forwards _diagramPulse_12m7d_1}._cardHeader_12m7d_283{align-items:center;gap:.5rem;margin-bottom:.5rem;display:flex}._cardTitle_12m7d_290{letter-spacing:-.2px;color:#fff;margin:0;font-size:1.1rem;font-weight:300}._bestAccuracyInline_12m7d_298{font-variant-numeric:tabular-nums;color:#00d4aa;margin-left:auto;font-size:.9rem;font-weight:500}._linearIssueLink_12m7d_306{max-width:100%;min-height:24px;color:var(--text-secondary);white-space:nowrap;background:#ffffff0a;border:1px solid #ffffff1a;align-items:center;gap:.3rem;padding:0 .35rem;font-size:.72rem;font-weight:600;text-decoration:none;display:inline-flex}._linearIssueLink_12m7d_306 span{text-overflow:ellipsis;min-width:0;overflow:hidden}._linearIssueLink_12m7d_306:hover{color:#fafafa;background:#ffffff12;border-color:#ffffff29}._linearIssueLink_12m7d_306 img{object-fit:contain;width:14px;height:14px;display:block}._statusBadge_12m7d_341{text-transform:uppercase;letter-spacing:1px;flex-shrink:0;padding:.2rem .6rem;font-size:.6rem;font-weight:500;display:inline-block}._detailTitleStack_12m7d_351{flex-direction:column;gap:.35rem;min-width:0;display:flex}._runProgressBlock_12m7d_358{background:#ffffff08;border:1px solid #ffffff14;margin-bottom:1rem;padding:.75rem}._runProgressHeader_12m7d_365{color:var(--text-secondary);font-variant-numeric:tabular-nums;justify-content:space-between;align-items:center;gap:1rem;margin-bottom:.45rem;font-size:.76rem;display:flex}._runProgressTrack_12m7d_376{background:#ffffff14;height:8px;overflow:hidden}._runProgressFill_12m7d_382{background:#00d4aa;height:100%}._runMetaGrid_12m7d_387{grid-template-columns:repeat(2,minmax(0,1fr));gap:.65rem;margin-bottom:1rem;display:grid}._runMetaCell_12m7d_394{background:#ffffff06;border:1px solid #ffffff12;min-width:0;padding:.6rem .65rem}._runMetaLabel_12m7d_401{color:var(--text-tertiary);letter-spacing:.04em;text-transform:uppercase;font-size:.65rem;font-weight:600;display:block}._runMetaValue_12m7d_410{min-width:0;color:var(--text-secondary);text-overflow:ellipsis;white-space:nowrap;margin-top:.18rem;font-size:.78rem;display:block;overflow:hidden}._detailEmpty_12m7d_421{color:var(--text-tertiary);background:#ffffff06;border:1px solid #ffffff12;padding:.75rem;font-size:.8rem}._metricsTable_12m7d_431{border-collapse:collapse;table-layout:fixed;width:100%;margin-bottom:1rem;font-size:.8rem}._metricsTable_12m7d_431 th,._metricsTable_12m7d_431 td{text-align:center;border-bottom:1px solid #ffffff0f;padding:.5rem}._metricsTable_12m7d_431 th{text-transform:uppercase;letter-spacing:.5px;color:var(--text-tertiary);cursor:help;text-underline-offset:3px;background:0 0;font-size:.7rem;font-weight:500;-webkit-text-decoration:underline dotted #fafafa33;text-decoration:underline dotted #fafafa33}._metricsTable_12m7d_431 td{color:var(--text-primary);font-variant-numeric:tabular-nums}._iterRowClickable_12m7d_463{cursor:pointer;transition:background .15s}._iterRowClickable_12m7d_463:hover{background:#ffffff0a}._iterRowExpanded_12m7d_472{background:#ffffff08}._iterRowExpanded_12m7d_472 td{border-bottom-color:#0000}._bestRow_12m7d_480{background:#00d4aa0f}._bestRow_12m7d_480._iterRowClickable_12m7d_463:hover{background:#00d4aa1a}._bestRow_12m7d_480 td{color:#00d4aa;font-weight:500}._iterDetailRow_12m7d_493 td{border-bottom:1px solid #ffffff0f;padding:0}._cardFooter_12m7d_498{color:var(--text-tertiary);letter-spacing:.2px;flex-wrap:wrap;justify-content:space-between;gap:.5rem .9rem;padding-top:.35rem;font-size:.7rem;display:flex}._footerUpdated_12m7d_509{margin-left:auto}._chartContainer_12m7d_515{background:#ffffff08;border:1px solid #ffffff14;padding:1.5rem}._chartTitle_12m7d_521{letter-spacing:-.3px;color:#fff;margin:0 0 1.25rem;font-size:1.25rem;font-weight:300}._chart_12m7d_515{flex-direction:column;gap:.35rem;display:flex}._chartRow_12m7d_535{align-items:center;gap:1rem;height:32px;display:flex}._chartLabel_12m7d_542{text-align:right;width:180px;color:var(--text-secondary);text-overflow:ellipsis;white-space:nowrap;flex-shrink:0;font-size:.75rem;font-weight:400;overflow:hidden}._chartBarContainer_12m7d_554{flex:1;align-items:center;gap:.5rem;display:flex}._chartBarTrack_12m7d_561{background:0 0;flex:1;height:24px;position:relative}._chartBar_12m7d_554{background:#00d4aa;height:100%;transition:width .3s}._chartRowClickable_12m7d_574{cursor:pointer;transition:background .15s}._chartRowClickable_12m7d_574:hover{background:#ffffff0a}._chartValue_12m7d_583{white-space:nowrap;color:var(--text-primary);font-variant-numeric:tabular-nums;text-align:right;flex-shrink:0;width:52px;font-size:.85rem;font-weight:500}._metricsTable_12m7d_431{border-collapse:collapse;width:100%;font-size:.85rem}._metricsTableHeader_12m7d_600{text-transform:uppercase;letter-spacing:.05em;color:var(--text-tertiary);text-align:left;border-bottom:1px solid #ffffff14;padding:.4rem .75rem;font-size:.7rem;font-weight:500}._metricsTableRow_12m7d_611{border-bottom:1px solid #ffffff0a}._metricsTableRow_12m7d_611:hover{background:#ffffff08}._metricsTableLabel_12m7d_619{color:var(--text-secondary);white-space:nowrap;padding:.5rem .75rem;font-weight:400}._metricsTableValue_12m7d_626{text-align:right;font-variant-numeric:tabular-nums;color:var(--text-primary);white-space:nowrap;padding:.5rem .75rem;font-weight:600}._metricsTableBarCell_12m7d_635{padding:.5rem .75rem}._metricsTableBarTrack_12m7d_639{background:#ffffff0f;border-radius:0;height:6px;overflow:hidden}._metricsTableBar_12m7d_635{background:#00d4aa;border-radius:0;height:100%;transition:width .3s}._chartItems_12m7d_653{color:var(--text-tertiary);text-align:right;font-variant-numeric:tabular-nums;flex-shrink:0;width:32px;font-size:.65rem}._noData_12m7d_662{color:var(--text-tertiary);text-align:center;padding:3rem;font-size:.9rem}._runSection_12m7d_669{margin-bottom:.75rem}._runSection_12m7d_669:last-child{margin-bottom:0}._runLabel_12m7d_677{text-transform:uppercase;letter-spacing:.5px;color:var(--text-tertiary);margin-bottom:.3rem;font-size:.65rem;font-weight:500;display:block}._treeForest_12m7d_689{margin-bottom:3rem;padding-bottom:2rem;overflow:auto hidden}._treeSvg_12m7d_696{flex-shrink:0;display:block}._treeNodeCard_12m7d_703{box-sizing:border-box;cursor:pointer;text-align:left;color:#fafafa;background:#0d0d0d;border:1px solid #ffffff14;flex-direction:column;width:100%;height:100%;padding:.5rem .6rem;font-family:Geist,ui-sans-serif,system-ui,-apple-system,sans-serif;transition:border-color .2s,box-shadow .2s,background .2s;display:flex;overflow:hidden}._treeNodeCard_12m7d_703:hover{background:#131313;border-color:#fff3}._treeNodeSelected_12m7d_733{background:#0b1210;border-color:#00d4aa80;box-shadow:0 0 12px #00d4aa1a}._treeNodeBest_12m7d_739{box-shadow:0 0 0 1px #00d4aa4d,0 0 16px #00d4aa14}@keyframes _nodeHighlight_12m7d_1{0%{border-color:#5b8def;box-shadow:0 0 24px #5b8def66,inset 0 0 12px #5b8def0d}70%{border-color:#5b8def99;box-shadow:0 0 16px #5b8def33}to{box-shadow:none;border-color:#ffffff14}}._treeNodeHighlight_12m7d_762{animation:5s ease-out forwards _nodeHighlight_12m7d_1}._treeNodeName_12m7d_766{color:#fff;-webkit-line-clamp:2;-webkit-box-orient:vertical;margin-bottom:.15rem;font-size:.65rem;font-weight:400;line-height:1.3;display:-webkit-box;overflow:hidden}._treeNodeBadgeRow_12m7d_778{align-items:center;gap:.3rem;margin-bottom:.15rem;display:flex}._treeNodeBadge_12m7d_778{text-transform:uppercase;letter-spacing:.5px;flex-shrink:0;padding:.1rem .3rem;font-size:.5rem;font-weight:500;display:inline-block}._treeNodeElapsed_12m7d_795{color:var(--text-tertiary);font-variant-numeric:tabular-nums;font-size:.5rem}._treeNodeScoreRow_12m7d_801{align-items:center;min-height:1.2rem;margin-bottom:.25rem;display:flex}._treeNodeIssueRow_12m7d_808{min-width:0;margin-top:auto}._treeNodeIssueRow_12m7d_808 ._linearIssueLink_12m7d_306{width:100%;min-height:22px;padding:0 .28rem;font-size:.58rem}._treeNodeIssueRow_12m7d_808 ._linearIssueLink_12m7d_306 img{width:12px;height:12px}._treeNodeAccuracy_12m7d_825{font-variant-numeric:tabular-nums;color:#00d4aa;letter-spacing:-.3px;font-size:1rem;font-weight:600}._treeNodeItems_12m7d_833{color:var(--text-tertiary);font-variant-numeric:tabular-nums;margin-left:.3rem;font-size:.6rem}._treeNodeLoading_12m7d_840{align-items:center;gap:.4rem;display:flex}@keyframes _pulse_12m7d_1{0%,to{opacity:.3}50%{opacity:1}}._treeNodePulse_12m7d_856{background:#f5a623;border-radius:0;width:6px;height:6px;animation:1.5s ease-in-out infinite _pulse_12m7d_1}._treeNodeLoadingText_12m7d_864{color:var(--text-tertiary);font-size:.7rem;font-weight:400}._detailPanelHeader_12m7d_872{align-items:center;gap:.5rem;margin-bottom:1.25rem;display:flex}._detailPanelTitle_12m7d_879{letter-spacing:-.3px;color:#fff;margin:0;font-size:1.3rem;font-weight:300}._tableWrapper_ftfpm_3{background:#ffffff06;border:1px solid #ffffff14;border-radius:0;margin:1rem 0 0;overflow-x:auto}._table_ftfpm_3{border-collapse:collapse;width:100%;font-family:Geist,ui-sans-serif,system-ui,sans-serif;font-size:.8rem}._noData_ftfpm_18{color:#ffffff4d;text-align:center;padding:2rem 0;font-style:italic}._table_ftfpm_3 thead{z-index:1;background:#101010;border-bottom:1px solid #ffffff1a;position:sticky;top:0}._table_ftfpm_3 th{text-align:right;color:#ffffff7a;letter-spacing:0;white-space:nowrap;-webkit-user-select:none;user-select:none;padding:.6rem .75rem;font-size:.72rem;font-weight:600}._thRank_ftfpm_46{width:2rem;text-align:center!important}._thName_ftfpm_51{min-width:180px;text-align:left!important}._thStatus_ftfpm_56{width:2.5rem;text-align:center!important}._thMetric_ftfpm_61{cursor:pointer;min-width:5rem;transition:color .15s}._thMetric_ftfpm_61:hover{color:#fffc}._thPrimary_ftfpm_71{color:#ffffff9e}._thPrimary_ftfpm_71:hover{color:#ffffffdb}._thSorted_ftfpm_79{color:#ffffffe6!important}._thPrimary_ftfpm_71._thSorted_ftfpm_79{color:#ffffffeb!important}._thLabel_ftfpm_87{margin-right:.3rem}._sortArrow_ftfpm_91{vertical-align:middle;opacity:.76;font-size:.62rem}._thItems_ftfpm_97{text-align:right;width:3rem}._thStarted_ftfpm_102{width:11rem;text-align:left!important}._row_ftfpm_109{cursor:pointer;will-change:transform;border-bottom:1px solid #ffffff0a;transition:background-color .15s}._row_ftfpm_109:hover{background:#ffffff0a}._rowBest_ftfpm_120{background:#ffffff0b}._rowBest_ftfpm_120:hover{background:#ffffff13}._rowSelected_ftfpm_128{box-shadow:inset 2px 0 #ffffff6b;background:#ffffff13!important}._table_ftfpm_3 td{text-align:right;color:#ffffffc7;font-variant-numeric:tabular-nums;padding:.55rem .75rem}._tdRank_ftfpm_142{color:#ffffff4d;font-size:.72rem;text-align:center!important}._tdName_ftfpm_148{align-items:center;gap:.5rem;display:flex;text-align:left!important}._expName_ftfpm_155{color:#ffffffe6;font-weight:450}._bestBadge_ftfpm_160{text-transform:uppercase;letter-spacing:.5px;color:#ffffffe0;background:#ffffff14;border:1px solid #ffffff29;border-radius:0;flex-shrink:0;padding:.1rem .35rem;font-size:.55rem;font-weight:600}._tdStatus_ftfpm_173{text-align:center!important}._statusDot_ftfpm_177{border-radius:0;width:7px;height:7px;display:inline-block}._tdMetric_ftfpm_184{font-family:Geist Mono,ui-monospace,monospace;font-size:.8rem}._tdPrimary_ftfpm_189{color:#ffffffeb;font-weight:500}._metricEmpty_ftfpm_198{color:#ffffff26}._tdItems_ftfpm_202{color:#ffffff4d;font-size:.72rem}._tdStarted_ftfpm_207{color:#ffffff73;white-space:nowrap;font-size:.72rem;text-align:left!important}:root{--bg-primary:#fff;--bg-chat:#fff;--bubble-user:#007aff;--bubble-user-text:#fff;--bubble-assistant:#e5e5ea;--bubble-assistant-text:#000;--header-bg:#f7f7f7eb;--header-border:#c8c8cc;--input-bg:#fff;--input-border:#c8c8cc;--text-secondary:#8e8e93;--font-family:-apple-system, BlinkMacSystemFont, "SF Pro Text", "SF Pro Display", "Helvetica Neue", Helvetica, Arial, sans-serif}@media (prefers-color-scheme:dark){:root{--bg-primary:#000;--bg-chat:#000;--bubble-user:#0b84fe;--bubble-user-text:#fff;--bubble-assistant:#26252a;--bubble-assistant-text:#fff;--header-bg:#1c1c1eeb;--header-border:#38383a;--input-bg:#1c1c1e;--input-border:#38383a;--text-secondary:#8e8e93}}:root{--bg-primary:#000;--bg-chat:#000;--text-primary:#fafafa;--text-secondary:#fafafab3;--text-tertiary:#fafafa80}*{box-sizing:border-box;margin:0;padding:0}html,body{height:100%;font-size:18px;font-family:var(--font-family);background:var(--bg-primary);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}#root{height:100%}
|