selftune 0.2.23 → 0.2.24

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.
Files changed (219) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +93 -15
  3. package/apps/local-dashboard/dist/assets/index-DgY2KGP-.css +1 -0
  4. package/apps/local-dashboard/dist/assets/index-Dmx7LPVX.js +15 -0
  5. package/apps/local-dashboard/dist/assets/vendor-react-C5oyHiV1.js +11 -0
  6. package/apps/local-dashboard/dist/assets/{vendor-table-BIiI3YhS.js → vendor-table-Bc_bbKd8.js} +1 -1
  7. package/apps/local-dashboard/dist/assets/vendor-ui-B3BPIYy7.js +1 -0
  8. package/apps/local-dashboard/dist/index.html +5 -5
  9. package/cli/selftune/adapters/codex/install.ts +310 -78
  10. package/cli/selftune/adapters/opencode/install.ts +3 -4
  11. package/cli/selftune/alpha-upload/build-payloads.ts +3 -3
  12. package/cli/selftune/alpha-upload/stage-canonical.ts +17 -11
  13. package/cli/selftune/auto-update.ts +200 -8
  14. package/cli/selftune/canonical-export.ts +55 -25
  15. package/cli/selftune/command-surface.ts +397 -0
  16. package/cli/selftune/contribute/contribute.ts +64 -13
  17. package/cli/selftune/contribution-config.ts +57 -3
  18. package/cli/selftune/contribution-preferences.ts +117 -0
  19. package/cli/selftune/contribution-signals.ts +8 -4
  20. package/cli/selftune/contribution-staging.ts +13 -2
  21. package/cli/selftune/contributions.ts +55 -121
  22. package/cli/selftune/creator-contributions.ts +29 -10
  23. package/cli/selftune/cron/setup.ts +7 -3
  24. package/cli/selftune/dashboard-contract.ts +73 -0
  25. package/cli/selftune/dashboard-server.ts +168 -17
  26. package/cli/selftune/dashboard.ts +350 -17
  27. package/cli/selftune/eval/baseline.ts +21 -5
  28. package/cli/selftune/eval/execution-eval.ts +170 -0
  29. package/cli/selftune/eval/family-overlap.ts +2 -2
  30. package/cli/selftune/eval/hooks-to-evals.ts +228 -82
  31. package/cli/selftune/eval/import-skillsbench.ts +2 -2
  32. package/cli/selftune/eval/invocation-classifier.ts +56 -0
  33. package/cli/selftune/eval/synthetic-evals.ts +5 -3
  34. package/cli/selftune/eval/unit-test-cli.ts +7 -4
  35. package/cli/selftune/evolution/apply-proposal.ts +295 -0
  36. package/cli/selftune/evolution/engines/replay-engine.ts +79 -57
  37. package/cli/selftune/evolution/evolve-body.ts +100 -39
  38. package/cli/selftune/evolution/evolve.ts +244 -52
  39. package/cli/selftune/evolution/rollback.ts +0 -1
  40. package/cli/selftune/evolution/validate-body.ts +68 -42
  41. package/cli/selftune/evolution/validate-host-replay.ts +510 -60
  42. package/cli/selftune/evolution/validate-proposal.ts +11 -150
  43. package/cli/selftune/evolution/validate-routing.ts +43 -41
  44. package/cli/selftune/evolution/validation-contract.ts +91 -0
  45. package/cli/selftune/grading/auto-grade.ts +11 -7
  46. package/cli/selftune/grading/grade-session.ts +10 -16
  47. package/cli/selftune/index.ts +35 -10
  48. package/cli/selftune/ingestors/claude-replay.ts +15 -10
  49. package/cli/selftune/ingestors/codex-wrapper.ts +3 -3
  50. package/cli/selftune/ingestors/opencode-ingest.ts +2 -2
  51. package/cli/selftune/ingestors/pi-ingest.ts +3 -2
  52. package/cli/selftune/init.ts +27 -3
  53. package/cli/selftune/localdb/direct-write.ts +35 -1
  54. package/cli/selftune/localdb/queries/cron.ts +34 -0
  55. package/cli/selftune/localdb/queries/dashboard.ts +834 -0
  56. package/cli/selftune/localdb/queries/evolution.ts +158 -0
  57. package/cli/selftune/localdb/queries/execution.ts +133 -0
  58. package/cli/selftune/localdb/queries/json.ts +18 -0
  59. package/cli/selftune/localdb/queries/monitoring.ts +263 -0
  60. package/cli/selftune/localdb/queries/raw.ts +95 -0
  61. package/cli/selftune/localdb/queries/staging.ts +270 -0
  62. package/cli/selftune/localdb/queries/trust.ts +392 -0
  63. package/cli/selftune/localdb/queries.ts +60 -2288
  64. package/cli/selftune/localdb/schema.ts +21 -0
  65. package/cli/selftune/monitoring/watch.ts +96 -29
  66. package/cli/selftune/normalization.ts +3 -0
  67. package/cli/selftune/observability.ts +4 -2
  68. package/cli/selftune/orchestrate/cli.ts +161 -0
  69. package/cli/selftune/orchestrate/execute.ts +295 -0
  70. package/cli/selftune/orchestrate/finalize.ts +157 -0
  71. package/cli/selftune/orchestrate/locks.ts +40 -0
  72. package/cli/selftune/orchestrate/plan.ts +131 -0
  73. package/cli/selftune/orchestrate/post-run.ts +59 -0
  74. package/cli/selftune/orchestrate/prepare.ts +334 -0
  75. package/cli/selftune/orchestrate/report.ts +182 -0
  76. package/cli/selftune/orchestrate/runtime.ts +120 -0
  77. package/cli/selftune/orchestrate/signals.ts +48 -0
  78. package/cli/selftune/orchestrate.ts +150 -1173
  79. package/cli/selftune/repair/skill-usage.ts +5 -2
  80. package/cli/selftune/routes/overview.ts +5 -2
  81. package/cli/selftune/routes/skill-report.ts +15 -2
  82. package/cli/selftune/schedule.ts +5 -5
  83. package/cli/selftune/status.ts +39 -2
  84. package/cli/selftune/testing-readiness.ts +597 -0
  85. package/cli/selftune/types.ts +44 -4
  86. package/cli/selftune/uninstall.ts +2 -1
  87. package/cli/selftune/utils/canonical-log.ts +1 -9
  88. package/cli/selftune/utils/cli-error.ts +9 -0
  89. package/cli/selftune/utils/llm-call.ts +126 -6
  90. package/cli/selftune/utils/skill-discovery.ts +2 -0
  91. package/cli/selftune/workflows/proposals.ts +184 -0
  92. package/cli/selftune/workflows/skill-scaffold.ts +241 -0
  93. package/cli/selftune/workflows/workflows.ts +100 -26
  94. package/node_modules/@selftune/telemetry-contract/fixtures/complete-push.ts +1 -1
  95. package/node_modules/@selftune/telemetry-contract/fixtures/evidence-only-push.ts +1 -1
  96. package/node_modules/@selftune/telemetry-contract/fixtures/partial-push-no-sessions.ts +1 -1
  97. package/node_modules/@selftune/telemetry-contract/fixtures/partial-push-unresolved-parents.ts +1 -1
  98. package/node_modules/@selftune/telemetry-contract/src/schemas.ts +41 -1
  99. package/node_modules/@selftune/telemetry-contract/src/types.ts +103 -2
  100. package/package.json +25 -9
  101. package/packages/dashboard-core/AGENTS.md +18 -0
  102. package/packages/dashboard-core/README.md +30 -0
  103. package/packages/dashboard-core/index.ts +3 -0
  104. package/packages/dashboard-core/package.json +39 -0
  105. package/packages/dashboard-core/src/chrome/DashboardChrome.tsx +74 -0
  106. package/packages/dashboard-core/src/chrome/DashboardHeader.tsx +200 -0
  107. package/packages/dashboard-core/src/chrome/DashboardSidebar.tsx +219 -0
  108. package/packages/dashboard-core/src/chrome/RuntimeBadge.tsx +46 -0
  109. package/packages/dashboard-core/src/chrome/index.ts +14 -0
  110. package/packages/dashboard-core/src/chrome/types.ts +81 -0
  111. package/packages/dashboard-core/src/chrome/utils.ts +23 -0
  112. package/packages/dashboard-core/src/gates/FeatureGate.tsx +11 -0
  113. package/packages/dashboard-core/src/gates/LockedRoute.tsx +29 -0
  114. package/packages/dashboard-core/src/gates/UpgradeCard.tsx +89 -0
  115. package/packages/dashboard-core/src/gates/index.ts +3 -0
  116. package/packages/dashboard-core/src/host/DashboardHostProvider.tsx +62 -0
  117. package/packages/dashboard-core/src/host/adapter.ts +47 -0
  118. package/packages/dashboard-core/src/host/capabilities.ts +55 -0
  119. package/packages/dashboard-core/src/host/index.ts +3 -0
  120. package/packages/dashboard-core/src/models/analytics.ts +39 -0
  121. package/packages/dashboard-core/src/models/index.ts +4 -0
  122. package/packages/dashboard-core/src/models/overview.ts +98 -0
  123. package/packages/dashboard-core/src/models/runtime.ts +7 -0
  124. package/packages/dashboard-core/src/models/skills.ts +34 -0
  125. package/packages/dashboard-core/src/routes/index.ts +2 -0
  126. package/packages/dashboard-core/src/routes/manifest.test.ts +70 -0
  127. package/packages/dashboard-core/src/routes/manifest.ts +451 -0
  128. package/packages/dashboard-core/src/routes/types.ts +39 -0
  129. package/packages/dashboard-core/src/screens/analytics/AnalyticsScreen.tsx +278 -0
  130. package/packages/dashboard-core/src/screens/analytics/index.ts +1 -0
  131. package/packages/dashboard-core/src/screens/index.ts +37 -0
  132. package/packages/dashboard-core/src/screens/overview/OverviewComparisonSurface.test.ts +101 -0
  133. package/packages/dashboard-core/src/screens/overview/OverviewComparisonSurface.tsx +393 -0
  134. package/packages/dashboard-core/src/screens/overview/OverviewCompositionSurface.test.tsx +113 -0
  135. package/packages/dashboard-core/src/screens/overview/OverviewCompositionSurface.tsx +72 -0
  136. package/packages/dashboard-core/src/screens/overview/OverviewCoreSurface.tsx +71 -0
  137. package/packages/dashboard-core/src/screens/overview/OverviewOnboardingBanner.tsx +90 -0
  138. package/packages/dashboard-core/src/screens/overview/OverviewRunSummary.tsx +40 -0
  139. package/packages/dashboard-core/src/screens/overview/index.ts +16 -0
  140. package/packages/dashboard-core/src/screens/overview/types.ts +13 -0
  141. package/packages/dashboard-core/src/screens/skill-report/SkillReportDailyBreakdownSection.tsx +99 -0
  142. package/packages/dashboard-core/src/screens/skill-report/SkillReportDataQualityTabContent.tsx +35 -0
  143. package/packages/dashboard-core/src/screens/skill-report/SkillReportEvidenceRail.tsx +71 -0
  144. package/packages/dashboard-core/src/screens/skill-report/SkillReportEvidenceSection.tsx +63 -0
  145. package/packages/dashboard-core/src/screens/skill-report/SkillReportEvidenceTabContent.tsx +25 -0
  146. package/packages/dashboard-core/src/screens/skill-report/SkillReportInvocationsSection.tsx +24 -0
  147. package/packages/dashboard-core/src/screens/skill-report/SkillReportMissedQueriesSection.tsx +79 -0
  148. package/packages/dashboard-core/src/screens/skill-report/SkillReportScaffold.tsx +150 -0
  149. package/packages/dashboard-core/src/screens/skill-report/SkillReportSections.test.tsx +224 -0
  150. package/packages/dashboard-core/src/screens/skill-report/SkillReportTabs.test.tsx +76 -0
  151. package/packages/dashboard-core/src/screens/skill-report/SkillReportTabs.tsx +88 -0
  152. package/packages/dashboard-core/src/screens/skill-report/SkillReportTrendSection.tsx +33 -0
  153. package/packages/dashboard-core/src/screens/skill-report/SkillReportTrustBadge.tsx +67 -0
  154. package/packages/dashboard-core/src/screens/skill-report/index.ts +45 -0
  155. package/packages/dashboard-core/src/screens/skills/SkillsLibraryScreen.tsx +162 -0
  156. package/packages/dashboard-core/src/screens/skills/index.ts +6 -0
  157. package/packages/telemetry-contract/fixtures/complete-push.ts +1 -1
  158. package/packages/telemetry-contract/fixtures/evidence-only-push.ts +1 -1
  159. package/packages/telemetry-contract/fixtures/partial-push-no-sessions.ts +1 -1
  160. package/packages/telemetry-contract/fixtures/partial-push-unresolved-parents.ts +1 -1
  161. package/packages/telemetry-contract/src/schemas.ts +41 -1
  162. package/packages/telemetry-contract/src/types.ts +103 -2
  163. package/packages/ui/src/components/EvidenceViewer.tsx +80 -25
  164. package/packages/ui/src/components/OverviewPanels.tsx +67 -26
  165. package/packages/ui/src/primitives/tabs.tsx +7 -6
  166. package/packages/ui/src/types.ts +10 -0
  167. package/skill/SKILL.md +130 -332
  168. package/skill/agents/diagnosis-analyst.md +3 -3
  169. package/skill/agents/evolution-reviewer.md +3 -3
  170. package/skill/agents/integration-guide.md +3 -3
  171. package/skill/agents/pattern-analyst.md +2 -2
  172. package/skill/references/cli-quick-reference.md +89 -0
  173. package/skill/references/creator-playbook.md +131 -0
  174. package/skill/references/examples.md +48 -0
  175. package/skill/references/troubleshooting.md +47 -0
  176. package/skill/references/version-history.md +1 -1
  177. package/skill/selftune.contribute.json +11 -0
  178. package/skill/{Workflows → workflows}/Baseline.md +20 -1
  179. package/skill/{Workflows → workflows}/Contribute.md +23 -10
  180. package/skill/{Workflows → workflows}/Contributions.md +13 -5
  181. package/skill/workflows/CreateTestDeploy.md +170 -0
  182. package/skill/{Workflows → workflows}/CreatorContributions.md +18 -6
  183. package/skill/{Workflows → workflows}/Cron.md +1 -1
  184. package/skill/{Workflows → workflows}/Dashboard.md +20 -0
  185. package/skill/{Workflows → workflows}/Doctor.md +1 -1
  186. package/skill/{Workflows → workflows}/Evals.md +67 -2
  187. package/skill/{Workflows → workflows}/Evolve.md +119 -30
  188. package/skill/{Workflows → workflows}/EvolveBody.md +41 -1
  189. package/skill/{Workflows → workflows}/Grade.md +1 -1
  190. package/skill/{Workflows → workflows}/Initialize.md +8 -4
  191. package/skill/{Workflows → workflows}/Orchestrate.md +13 -3
  192. package/skill/{Workflows → workflows}/Schedule.md +3 -3
  193. package/skill/workflows/SignalsDashboard.md +87 -0
  194. package/skill/{Workflows → workflows}/UnitTest.md +19 -0
  195. package/skill/{Workflows → workflows}/Watch.md +42 -2
  196. package/skill/{Workflows → workflows}/Workflows.md +39 -2
  197. package/apps/local-dashboard/dist/assets/index-CwOtTrUS.css +0 -1
  198. package/apps/local-dashboard/dist/assets/index-f1HQpbeH.js +0 -59
  199. package/apps/local-dashboard/dist/assets/vendor-react-CKkiCskZ.js +0 -11
  200. package/apps/local-dashboard/dist/assets/vendor-ui-jVSaIZey.js +0 -12
  201. /package/skill/{Workflows → workflows}/AlphaUpload.md +0 -0
  202. /package/skill/{Workflows → workflows}/AutoActivation.md +0 -0
  203. /package/skill/{Workflows → workflows}/Badge.md +0 -0
  204. /package/skill/{Workflows → workflows}/Composability.md +0 -0
  205. /package/skill/{Workflows → workflows}/EvolutionMemory.md +0 -0
  206. /package/skill/{Workflows → workflows}/ExportCanonical.md +0 -0
  207. /package/skill/{Workflows → workflows}/Hook.md +0 -0
  208. /package/skill/{Workflows → workflows}/ImportSkillsBench.md +0 -0
  209. /package/skill/{Workflows → workflows}/Ingest.md +0 -0
  210. /package/skill/{Workflows → workflows}/PlatformHooks.md +0 -0
  211. /package/skill/{Workflows → workflows}/Quickstart.md +0 -0
  212. /package/skill/{Workflows → workflows}/Recover.md +0 -0
  213. /package/skill/{Workflows → workflows}/Registry.md +0 -0
  214. /package/skill/{Workflows → workflows}/RepairSkillUsage.md +0 -0
  215. /package/skill/{Workflows → workflows}/Replay.md +0 -0
  216. /package/skill/{Workflows → workflows}/Rollback.md +0 -0
  217. /package/skill/{Workflows → workflows}/Sync.md +0 -0
  218. /package/skill/{Workflows → workflows}/Telemetry.md +0 -0
  219. /package/skill/{Workflows → workflows}/Uninstall.md +0 -0
@@ -1,5 +1,6 @@
1
1
  "use client";
2
2
 
3
+ import type { ReactNode } from "react";
3
4
  import { useMemo, useState } from "react";
4
5
  import { CheckCircleIcon, ChevronDownIcon } from "lucide-react";
5
6
 
@@ -95,7 +96,22 @@ const BUCKET_CFG: Record<TrustBucket, { label: string; accent: string; dot: stri
95
96
  };
96
97
 
97
98
  // Ambient bar heights for hero background
98
- const BARS = [35, 55, 40, 70, 45, 80, 30, 65, 50, 75, 38, 60, 42, 72];
99
+ const BARS = [
100
+ { id: "autonomy-bar-1", height: 35 },
101
+ { id: "autonomy-bar-2", height: 55 },
102
+ { id: "autonomy-bar-3", height: 40 },
103
+ { id: "autonomy-bar-4", height: 70 },
104
+ { id: "autonomy-bar-5", height: 45 },
105
+ { id: "autonomy-bar-6", height: 80 },
106
+ { id: "autonomy-bar-7", height: 30 },
107
+ { id: "autonomy-bar-8", height: 65 },
108
+ { id: "autonomy-bar-9", height: 50 },
109
+ { id: "autonomy-bar-10", height: 75 },
110
+ { id: "autonomy-bar-11", height: 38 },
111
+ { id: "autonomy-bar-12", height: 60 },
112
+ { id: "autonomy-bar-13", height: 42 },
113
+ { id: "autonomy-bar-14", height: 72 },
114
+ ] as const;
99
115
 
100
116
  // ---------------------------------------------------------------------------
101
117
  // AutonomyHeroCard
@@ -104,9 +120,10 @@ const BARS = [35, 55, 40, 70, 45, 80, 30, 65, 50, 75, 38, 60, 42, 72];
104
120
  export interface AutonomyHeroCardProps {
105
121
  status: AutonomyStatus;
106
122
  lastRun: string | null;
123
+ actions?: ReactNode;
107
124
  }
108
125
 
109
- export function AutonomyHeroCard({ status, lastRun }: AutonomyHeroCardProps) {
126
+ export function AutonomyHeroCard({ status, lastRun, actions }: AutonomyHeroCardProps) {
110
127
  const dot = STATUS_DOT[status.level];
111
128
  const primaryStat =
112
129
  status.attention_required > 0
@@ -117,13 +134,13 @@ export function AutonomyHeroCard({ status, lastRun }: AutonomyHeroCardProps) {
117
134
  <Card className="relative min-h-[332px] border-none bg-gradient-to-br from-muted via-muted to-primary/5 shadow-none py-0 ring-0">
118
135
  {/* Ambient bars */}
119
136
  <div className="absolute inset-0 flex items-end justify-around px-8 pb-24 pt-20 opacity-[0.08] pointer-events-none">
120
- {BARS.map((h, i) => (
137
+ {BARS.map((bar) => (
121
138
  <div
122
- key={i}
139
+ key={bar.id}
123
140
  className="flex-1 rounded-t-sm min-w-[12px]"
124
141
  style={{
125
- height: `${h}%`,
126
- backgroundColor: `rgba(79, 242, 255, ${0.15 + (h / 100) * 0.3})`,
142
+ height: `${bar.height}%`,
143
+ backgroundColor: `rgba(79, 242, 255, ${0.15 + (bar.height / 100) * 0.3})`,
127
144
  }}
128
145
  />
129
146
  ))}
@@ -188,16 +205,17 @@ export function AutonomyHeroCard({ status, lastRun }: AutonomyHeroCardProps) {
188
205
  </div>
189
206
  </div>
190
207
 
191
- {status.attention_required > 0 ? (
192
- <a
193
- href="#supervision-feed"
194
- className="inline-flex items-center justify-center rounded-lg bg-primary px-4 py-2 text-sm font-medium text-primary-foreground transition-colors hover:bg-primary/80 w-fit"
195
- >
196
- Review Attention Queue
197
- </a>
198
- ) : (
199
- <span className="text-sm text-muted-foreground/70">No action needed</span>
200
- )}
208
+ {actions ??
209
+ (status.attention_required > 0 ? (
210
+ <a
211
+ href="#supervision-feed"
212
+ className="inline-flex w-fit items-center justify-center rounded-lg bg-primary px-4 py-2 text-sm font-medium text-primary-foreground transition-colors hover:bg-primary/80"
213
+ >
214
+ Review Attention Queue
215
+ </a>
216
+ ) : (
217
+ <span className="text-sm text-muted-foreground/70">No action needed</span>
218
+ ))}
201
219
  </CardContent>
202
220
  </Card>
203
221
  );
@@ -210,10 +228,11 @@ export function AutonomyHeroCard({ status, lastRun }: AutonomyHeroCardProps) {
210
228
  export interface TrustWatchlistRailProps {
211
229
  entries: TrustWatchlistEntry[];
212
230
  /** Optional render prop for skill name links */
213
- renderSkillLink?: (skillName: string) => React.ReactNode;
231
+ renderSkillLink?: (skillName: string) => ReactNode;
232
+ footer?: ReactNode;
214
233
  }
215
234
 
216
- export function TrustWatchlistRail({ entries, renderSkillLink }: TrustWatchlistRailProps) {
235
+ export function TrustWatchlistRail({ entries, renderSkillLink, footer }: TrustWatchlistRailProps) {
217
236
  const buckets = useMemo(() => {
218
237
  const order: TrustBucket[] = ["at_risk", "improving", "uncertain", "stable"];
219
238
  const grouped: Record<TrustBucket, TrustWatchlistEntry[]> = {
@@ -229,7 +248,10 @@ export function TrustWatchlistRail({ entries, renderSkillLink }: TrustWatchlistR
229
248
  }, [entries]);
230
249
 
231
250
  return (
232
- <Card className="border-none bg-muted shadow-none py-0 max-h-[360px] ring-0">
251
+ <Card
252
+ data-parity-root="overview-trust-watchlist"
253
+ className="border-none bg-muted shadow-none py-0 max-h-[360px] ring-0"
254
+ >
233
255
  <CardHeader className="px-5 pt-5 pb-0">
234
256
  <div>
235
257
  <p className="text-[10px] uppercase tracking-[0.2em] text-muted-foreground">
@@ -262,6 +284,10 @@ export function TrustWatchlistRail({ entries, renderSkillLink }: TrustWatchlistR
262
284
  ))}
263
285
  </CardContent>
264
286
  )}
287
+
288
+ {footer ? (
289
+ <CardContent className="mt-auto px-5 pb-5 pt-1 shrink-0">{footer}</CardContent>
290
+ ) : null}
265
291
  </Card>
266
292
  );
267
293
  }
@@ -273,7 +299,7 @@ function RailBucket({
273
299
  }: {
274
300
  bucket: TrustBucket;
275
301
  items: TrustWatchlistEntry[];
276
- renderSkillLink?: (skillName: string) => React.ReactNode;
302
+ renderSkillLink?: (skillName: string) => ReactNode;
277
303
  }) {
278
304
  const cfg = BUCKET_CFG[bucket];
279
305
  const [open, setOpen] = useState(false);
@@ -342,13 +368,14 @@ export interface SupervisionFeedProps {
342
368
  attention: AttentionItem[];
343
369
  decisions: AutonomousDecision[];
344
370
  /** Optional render prop for skill name links */
345
- renderSkillLink?: (skillName: string) => React.ReactNode;
371
+ renderSkillLink?: (skillName: string) => ReactNode;
346
372
  }
347
373
 
348
374
  export function SupervisionFeed({ attention, decisions, renderSkillLink }: SupervisionFeedProps) {
349
375
  return (
350
376
  <Card
351
377
  id="supervision-feed"
378
+ data-parity-root="overview-supervision-feed"
352
379
  className="relative overflow-hidden border-none bg-muted shadow-none py-0 scroll-mt-6 ring-0"
353
380
  >
354
381
  <div className="pointer-events-none absolute inset-x-0 top-0 h-20 bg-gradient-to-b from-primary/5 via-transparent to-transparent" />
@@ -398,7 +425,7 @@ function AttentionContent({
398
425
  renderSkillLink,
399
426
  }: {
400
427
  attention: AttentionItem[];
401
- renderSkillLink?: (skillName: string) => React.ReactNode;
428
+ renderSkillLink?: (skillName: string) => ReactNode;
402
429
  }) {
403
430
  const [showAll, setShowAll] = useState(false);
404
431
 
@@ -468,10 +495,24 @@ function DecisionsContent({
468
495
  renderSkillLink,
469
496
  }: {
470
497
  decisions: AutonomousDecision[];
471
- renderSkillLink?: (skillName: string) => React.ReactNode;
498
+ renderSkillLink?: (skillName: string) => ReactNode;
472
499
  }) {
473
500
  const [showAll, setShowAll] = useState(false);
474
501
  const visible = showAll ? decisions : decisions.slice(0, 10);
502
+ const keyedVisible = useMemo(() => {
503
+ const seen = new Map<string, number>();
504
+
505
+ return visible.map((decision) => {
506
+ const baseKey = `${decision.timestamp}-${decision.skill_name}-${decision.kind}`;
507
+ const occurrence = seen.get(baseKey) ?? 0;
508
+ seen.set(baseKey, occurrence + 1);
509
+
510
+ return {
511
+ decision,
512
+ key: `${baseKey}-${occurrence}`,
513
+ };
514
+ });
515
+ }, [visible]);
475
516
 
476
517
  if (decisions.length === 0) {
477
518
  return <p className="text-xs text-muted-foreground/70 py-4">No autonomous decisions yet.</p>;
@@ -479,11 +520,11 @@ function DecisionsContent({
479
520
 
480
521
  return (
481
522
  <div className="space-y-1">
482
- {visible.map((d, i) => {
523
+ {keyedVisible.map(({ decision: d, key }) => {
483
524
  const marker = DECISION_MARKERS[d.kind];
484
525
  return (
485
526
  <div
486
- key={`${d.timestamp}-${d.skill_name}-${i}`}
527
+ key={key}
487
528
  className="flex items-start gap-2.5 rounded-xl bg-background/30 px-3 py-2 transition-colors hover:bg-background/45"
488
529
  >
489
530
  <span className={`mt-1.5 size-2 shrink-0 rounded-full ${marker}`} />
@@ -535,7 +576,7 @@ export interface SkillComparisonRow {
535
576
  export interface SkillComparisonGridProps {
536
577
  rows: SkillComparisonRow[];
537
578
  /** Optional render prop for skill name links */
538
- renderSkillLink?: (skillName: string) => React.ReactNode;
579
+ renderSkillLink?: (skillName: string) => ReactNode;
539
580
  }
540
581
 
541
582
  function formatEvolutionAction(action: string): string {
@@ -17,12 +17,12 @@ function Tabs({ className, orientation = "horizontal", ...props }: TabsPrimitive
17
17
  }
18
18
 
19
19
  const tabsListVariants = cva(
20
- "group/tabs-list inline-flex w-fit items-center justify-center rounded-lg p-[3px] text-muted-foreground group-data-horizontal/tabs:h-8 group-data-vertical/tabs:h-fit group-data-vertical/tabs:flex-col data-[variant=line]:rounded-none",
20
+ "group/tabs-list inline-flex w-fit items-center justify-center text-muted-foreground group-data-horizontal/tabs:h-8 group-data-vertical/tabs:h-fit group-data-vertical/tabs:flex-col",
21
21
  {
22
22
  variants: {
23
23
  variant: {
24
- default: "bg-muted",
25
- line: "gap-1 bg-transparent",
24
+ default: "rounded-lg bg-muted p-[3px]",
25
+ line: "gap-1 bg-transparent p-0 data-[variant=line]:h-auto",
26
26
  },
27
27
  },
28
28
  defaultVariants: {
@@ -51,9 +51,10 @@ function TabsTrigger({ className, ...props }: TabsPrimitive.Tab.Props) {
51
51
  <TabsPrimitive.Tab
52
52
  data-slot="tabs-trigger"
53
53
  className={cn(
54
- "relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-1.5 py-0.5 text-sm font-medium whitespace-nowrap text-foreground/60 transition-all group-data-vertical/tabs:w-full group-data-vertical/tabs:justify-start hover:text-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1 focus-visible:outline-ring disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 dark:text-muted-foreground dark:hover:text-foreground group-data-[variant=default]/tabs-list:data-active:shadow-sm group-data-[variant=line]/tabs-list:data-active:shadow-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
55
- "group-data-[variant=line]/tabs-list:bg-transparent group-data-[variant=line]/tabs-list:data-active:bg-transparent dark:group-data-[variant=line]/tabs-list:data-active:border-transparent dark:group-data-[variant=line]/tabs-list:data-active:bg-transparent",
56
- "data-active:bg-background data-active:text-foreground dark:data-active:border-input dark:data-active:bg-input/30 dark:data-active:text-foreground",
54
+ "relative inline-flex flex-1 items-center justify-center gap-1.5 text-sm font-medium whitespace-nowrap text-foreground/60 transition-all group-data-horizontal/tabs:h-[calc(100%-1px)] group-data-horizontal/tabs:px-1.5 group-data-horizontal/tabs:py-0.5 group-data-vertical/tabs:w-full group-data-vertical/tabs:justify-start group-data-vertical/tabs:px-1.5 group-data-vertical/tabs:py-0.5 hover:text-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1 focus-visible:outline-ring disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 dark:text-muted-foreground dark:hover:text-foreground group-data-[variant=default]/tabs-list:rounded-md group-data-[variant=default]/tabs-list:border group-data-[variant=default]/tabs-list:border-transparent group-data-[variant=default]/tabs-list:data-active:shadow-sm group-data-[variant=line]/tabs-list:data-active:shadow-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
55
+ "group-data-[variant=line]/tabs-list:h-auto group-data-[variant=line]/tabs-list:flex-none group-data-[variant=line]/tabs-list:rounded-none group-data-[variant=line]/tabs-list:border-0 group-data-[variant=line]/tabs-list:bg-transparent group-data-[variant=line]/tabs-list:px-2 group-data-[variant=line]/tabs-list:py-1 group-data-[variant=line]/tabs-list:data-active:bg-transparent dark:group-data-[variant=line]/tabs-list:data-active:border-transparent dark:group-data-[variant=line]/tabs-list:data-active:bg-transparent",
56
+ "group-data-[variant=default]/tabs-list:data-active:bg-background group-data-[variant=default]/tabs-list:data-active:text-foreground dark:group-data-[variant=default]/tabs-list:data-active:border-input dark:group-data-[variant=default]/tabs-list:data-active:bg-input/30",
57
+ "group-data-[variant=line]/tabs-list:data-active:text-foreground",
57
58
  "after:absolute after:bg-foreground after:opacity-0 after:transition-opacity group-data-horizontal/tabs:after:inset-x-0 group-data-horizontal/tabs:after:bottom-[-5px] group-data-horizontal/tabs:after:h-0.5 group-data-vertical/tabs:after:inset-y-0 group-data-vertical/tabs:after:-right-1 group-data-vertical/tabs:after:w-0.5 group-data-[variant=line]/tabs-list:data-active:after:opacity-100",
58
59
  className,
59
60
  )}
@@ -50,6 +50,16 @@ export interface EvalSnapshot {
50
50
  improved?: boolean;
51
51
  regressions?: Array<Record<string, unknown>>;
52
52
  new_passes?: Array<Record<string, unknown>>;
53
+ per_entry_results?: Array<Record<string, unknown>>;
54
+ before_entry_results?: Array<Record<string, unknown>>;
55
+ gates_passed?: number;
56
+ gates_total?: number;
57
+ gate_results?: Array<Record<string, unknown>>;
58
+ validation_mode?: string;
59
+ validation_agent?: string;
60
+ validation_fixture_id?: string;
61
+ validation_fallback_reason?: string;
62
+ validation_evidence_ref?: string;
53
63
  }
54
64
 
55
65
  export interface EvolutionEntry {