completion-kit 0.7.0 → 0.9.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.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/stylesheets/completion_kit/application.css +146 -325
  3. data/app/controllers/completion_kit/api/v1/base_controller.rb +14 -4
  4. data/app/controllers/completion_kit/api/v1/calibrations_controller.rb +2 -2
  5. data/app/controllers/completion_kit/api/v1/datasets_controller.rb +2 -2
  6. data/app/controllers/completion_kit/api/v1/metric_groups_controller.rb +2 -2
  7. data/app/controllers/completion_kit/api/v1/metric_versions_controller.rb +1 -1
  8. data/app/controllers/completion_kit/api/v1/metrics_controller.rb +5 -32
  9. data/app/controllers/completion_kit/api/v1/prompts_controller.rb +2 -2
  10. data/app/controllers/completion_kit/api/v1/provider_credentials_controller.rb +2 -2
  11. data/app/controllers/completion_kit/api/v1/runs_controller.rb +7 -7
  12. data/app/controllers/completion_kit/api/v1/tags_controller.rb +2 -2
  13. data/app/controllers/completion_kit/metrics_controller.rb +14 -37
  14. data/app/controllers/completion_kit/runs_controller.rb +2 -2
  15. data/app/jobs/completion_kit/generate_row_job.rb +2 -4
  16. data/app/jobs/completion_kit/judge_review_job.rb +4 -19
  17. data/app/models/completion_kit/metric.rb +0 -1
  18. data/app/models/completion_kit/metric_version.rb +35 -0
  19. data/app/models/completion_kit/run.rb +0 -1
  20. data/app/services/completion_kit/judge_service.rb +3 -10
  21. data/app/services/completion_kit/mcp_tools/metric_versions.rb +1 -1
  22. data/app/services/completion_kit/metric_variant_generator.rb +0 -13
  23. data/app/views/completion_kit/api_reference/_body.html.erb +2 -12
  24. data/app/views/completion_kit/api_reference/index.html.erb +4 -0
  25. data/app/views/completion_kit/calibrations/_trust_panel.html.erb +19 -12
  26. data/app/views/completion_kit/metrics/_form.html.erb +11 -12
  27. data/app/views/completion_kit/metrics/edit.html.erb +18 -0
  28. data/app/views/completion_kit/metrics/index.html.erb +0 -17
  29. data/app/views/completion_kit/metrics/show.html.erb +87 -105
  30. data/app/views/completion_kit/responses/show.html.erb +2 -2
  31. data/app/views/completion_kit/runs/show.html.erb +7 -7
  32. data/config/routes.rb +0 -4
  33. data/db/migrate/20260529000001_remove_few_shot_examples_from_completion_kit_metrics.rb +5 -0
  34. data/lib/completion_kit/version.rb +1 -1
  35. metadata +2 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 285fba79d665c4fe077b42f0e8ce888ce84a314b95698a561eea9fb48c75b045
4
- data.tar.gz: a984971e294bda341824e3696cab11662f82fcee2c50974798356754ba55126c
3
+ metadata.gz: ddf80d4e74705494435d5ae2d9f0ed5ce0dd927f32bffcb1a13819076f94bced
4
+ data.tar.gz: 74eadf6abc0f173d0047c961502aeaaab9b5b3de7dd155a00d5d054fb5b8f6e6
5
5
  SHA512:
6
- metadata.gz: 1a12beaf77a9d8071949bede78336910eb8da43598609ac6307e09493d1c088a82cc3056ccaf63b3ae4eeb4ea022d19c182a05c0f037bc8a31ba21246cc5bd56
7
- data.tar.gz: e007e6eeb9f7e89f3aa5ba8397338ce19778b5040f184b8cb6c012faf3f6ea464f6c3d5423fd7f7b36882494fbb90d70e068da7fe15bb76e67e9992585ba80c6
6
+ metadata.gz: fa0c962d8282310584ff52a849eeb7efc3c66debe9246d8231e5e24e55c45e8566b4edf83a19d3a021dc4a41b6241c042e0af3059c1b47ba709412220628ed96
7
+ data.tar.gz: 20cdeabe363e212a572cbe6b1f08128a7aae88f5a2ef50a3b3d012e5fbef2a64c93571bc6ebb28e971dc819ac57d060a11a3006f1b7a60ebeb265957be221eab
@@ -216,6 +216,10 @@ form.button_to {
216
216
  justify-content: flex-end;
217
217
  flex-shrink: 0;
218
218
  }
219
+ .ck-actions .ck-icon-btn {
220
+ width: 2rem;
221
+ height: 2rem;
222
+ }
219
223
 
220
224
  .ck-toolbar__spacer {
221
225
  flex: 1;
@@ -298,6 +302,11 @@ form.button_to {
298
302
  margin-right: 0.75rem;
299
303
  }
300
304
 
305
+ .ck-title--sm {
306
+ font-size: clamp(1.1rem, 1.6vw, 1.4rem);
307
+ line-height: 1.25;
308
+ }
309
+
301
310
  .ck-section-title {
302
311
  font-size: 1.35rem;
303
312
  }
@@ -660,6 +669,33 @@ tr:hover .ck-chip--publish {
660
669
  border-color: var(--ck-accent);
661
670
  color: var(--ck-accent);
662
671
  }
672
+ .ck-chip--cta {
673
+ cursor: pointer;
674
+ background: var(--ck-accent-soft);
675
+ border-color: rgba(56, 189, 248, 0.4);
676
+ color: var(--ck-accent);
677
+ transition: border-color 0.15s, color 0.15s;
678
+ }
679
+ .ck-chip--cta:hover {
680
+ border-color: var(--ck-accent);
681
+ color: var(--ck-accent-hover);
682
+ }
683
+ .ck-version-created {
684
+ display: flex;
685
+ align-items: center;
686
+ justify-content: space-between;
687
+ gap: 10px;
688
+ }
689
+ .ck-version-state {
690
+ font-family: var(--ck-mono);
691
+ font-size: 0.66rem;
692
+ letter-spacing: 0.07em;
693
+ text-transform: uppercase;
694
+ color: var(--ck-dim);
695
+ }
696
+ .ck-version-state--live {
697
+ color: var(--ck-text);
698
+ }
663
699
 
664
700
  .ck-chip--soft {
665
701
  background: var(--ck-accent-soft);
@@ -748,6 +784,11 @@ tr:hover .ck-chip--publish {
748
784
  flex-shrink: 0;
749
785
  color: var(--ck-warning);
750
786
  }
787
+ .ck-kicker--icon {
788
+ display: inline-flex;
789
+ align-items: center;
790
+ gap: 0.4rem;
791
+ }
751
792
 
752
793
  .ck-button:hover {
753
794
  transform: translateY(-1px);
@@ -2547,6 +2588,26 @@ select.ck-input {
2547
2588
  gap: 0.6rem;
2548
2589
  padding: 0.95rem 1.5rem 1.1rem;
2549
2590
  }
2591
+ .ck-modal__footer--split {
2592
+ justify-content: space-between;
2593
+ align-items: center;
2594
+ gap: 1rem;
2595
+ flex-wrap: wrap;
2596
+ border-top: 1px solid var(--ck-line);
2597
+ }
2598
+ .ck-modal__foot-note {
2599
+ color: var(--ck-dim);
2600
+ font-size: 0.86rem;
2601
+ }
2602
+ .ck-modal__foot-actions {
2603
+ display: inline-flex;
2604
+ align-items: center;
2605
+ gap: 0.6rem;
2606
+ }
2607
+ .ck-modal__foot-actions .ck-icon-btn {
2608
+ width: 2rem;
2609
+ height: 2rem;
2610
+ }
2550
2611
 
2551
2612
  .ck-modal__close-btn {
2552
2613
  appearance: none;
@@ -3577,52 +3638,59 @@ select.ck-input {
3577
3638
  .ck-prompt-versions-table th:nth-child(3), .ck-prompt-versions-table td:nth-child(3) { width: 8rem; white-space: nowrap; }
3578
3639
  .ck-prompt-versions-table th:nth-child(4), .ck-prompt-versions-table td:nth-child(4) { width: auto; }
3579
3640
 
3580
- .ck-metric-versions-table th:nth-child(1), .ck-metric-versions-table td:nth-child(1) { width: 16rem; }
3581
- .ck-metric-versions-table th:nth-child(2), .ck-metric-versions-table td:nth-child(2) { width: 12rem; white-space: nowrap; }
3582
- .ck-metric-versions-table th:nth-child(3), .ck-metric-versions-table td:nth-child(3) { width: auto; }
3641
+ .ck-metric-versions-table th:nth-child(1), .ck-metric-versions-table td:nth-child(1) { width: 14rem; }
3642
+ .ck-metric-versions-table th:nth-child(2), .ck-metric-versions-table td:nth-child(2) { width: auto; }
3643
+ .ck-metric-versions-table th:nth-child(3), .ck-metric-versions-table td:nth-child(3) { width: 9rem; white-space: nowrap; }
3644
+ .ck-metric-versions-table th:nth-child(4), .ck-metric-versions-table td:nth-child(4) { width: 9rem; white-space: nowrap; }
3645
+
3646
+ .ck-change-link {
3647
+ background: none;
3648
+ border: 0;
3649
+ padding: 0;
3650
+ cursor: pointer;
3651
+ font-family: inherit;
3652
+ font-size: 0.86rem;
3653
+ text-align: left;
3654
+ color: var(--ck-text);
3655
+ }
3656
+ .ck-change-link:hover,
3657
+ .ck-change-link:focus-visible {
3658
+ color: var(--ck-accent);
3659
+ text-decoration: underline;
3660
+ }
3661
+ .ck-change-link--trivial {
3662
+ color: var(--ck-dim);
3663
+ }
3664
+ .ck-change-link--major {
3665
+ color: rgb(217, 119, 6);
3666
+ }
3583
3667
 
3584
3668
  .ck-source-chip {
3585
3669
  display: inline-block;
3586
- padding: 2px 8px;
3587
- border-radius: 4px;
3588
3670
  font-family: var(--ck-mono);
3589
- font-size: 0.7rem;
3671
+ font-size: 0.68rem;
3590
3672
  letter-spacing: 0.06em;
3591
3673
  text-transform: uppercase;
3592
- border: 1px solid var(--ck-line-strong);
3593
- background: var(--ck-surface-soft);
3594
3674
  color: var(--ck-muted);
3595
3675
  }
3596
3676
  .ck-source-chip--ai {
3597
- border-color: rgba(56, 189, 248, 0.35);
3598
- background: rgba(56, 189, 248, 0.08);
3599
3677
  color: var(--ck-accent);
3600
3678
  }
3601
3679
  .ck-source-chip--manual {
3602
- border-color: var(--ck-line-strong);
3603
3680
  color: var(--ck-text);
3604
3681
  }
3605
3682
  .ck-source-chip--initial {
3606
- border-color: var(--ck-line);
3607
3683
  color: var(--ck-dim);
3608
3684
  }
3609
3685
  .ck-source-chip--revert {
3610
- border-color: rgba(245, 158, 11, 0.35);
3611
- background: rgba(245, 158, 11, 0.08);
3612
3686
  color: rgb(217, 119, 6);
3613
3687
  }
3614
3688
  .ck-source-chip--current {
3615
- border-color: var(--ck-line-strong);
3616
3689
  color: var(--ck-text);
3617
3690
  }
3618
3691
  .ck-source-chip--past {
3619
- border-color: var(--ck-line);
3620
3692
  color: var(--ck-dim);
3621
3693
  }
3622
- .ck-disagreement--stale {
3623
- opacity: 0.7;
3624
- }
3625
-
3626
3694
  .ck-suggestions-table th:nth-child(1), .ck-suggestions-table td:nth-child(1) { width: 16rem; white-space: nowrap; }
3627
3695
  .ck-suggestions-table th:nth-child(2), .ck-suggestions-table td:nth-child(2) { width: auto; }
3628
3696
  .ck-suggestions-table th:nth-child(3), .ck-suggestions-table td:nth-child(3) { width: 6rem; white-space: nowrap; }
@@ -5547,224 +5615,80 @@ a.tag-mark {
5547
5615
  font-weight: 600;
5548
5616
  }
5549
5617
 
5550
- .ck-trust-panel {
5551
- display: inline-flex;
5552
- flex-direction: column;
5553
- gap: 6px;
5554
- margin-top: 12px;
5555
- padding: 10px 14px;
5556
- background: var(--ck-surface-soft);
5557
- border: 1px solid var(--ck-line);
5558
- border-radius: 6px;
5559
- }
5560
- .ck-trust-panel__label {
5561
- margin: 0;
5562
- font-family: var(--ck-mono);
5563
- font-size: 0.7rem;
5564
- letter-spacing: 0.08em;
5565
- text-transform: uppercase;
5566
- color: var(--ck-dim);
5567
- }
5568
- .ck-trust-panel__body {
5618
+ .ck-trust-line {
5619
+ margin: 14px 0 0;
5569
5620
  display: flex;
5621
+ flex-wrap: wrap;
5570
5622
  align-items: baseline;
5571
- gap: 10px;
5572
- }
5573
- .ck-trust-panel__counter {
5574
- font-family: var(--ck-mono);
5575
- font-size: 1.6rem;
5576
- font-weight: 600;
5577
- color: var(--ck-accent);
5578
- }
5579
- .ck-trust-panel__counter-of {
5580
- font-size: 0.9rem;
5581
- color: var(--ck-dim);
5582
- margin-left: 4px;
5583
- }
5584
- .ck-trust-panel__hint {
5585
- font-family: var(--ck-mono);
5586
- font-size: 0.72rem;
5587
- color: var(--ck-dim);
5588
- letter-spacing: 0.04em;
5589
- }
5590
- .ck-trust-panel__score {
5591
- font-family: var(--ck-mono);
5592
- font-size: 1.6rem;
5593
- font-weight: 600;
5594
- color: var(--ck-success);
5595
- }
5596
- .ck-trust-panel__score-pct {
5597
- font-size: 0.9rem;
5598
- color: var(--ck-dim);
5599
- margin-left: 2px;
5600
- }
5601
- .ck-trust-panel__margin {
5623
+ gap: 6px 20px;
5602
5624
  font-family: var(--ck-mono);
5603
5625
  font-size: 0.8rem;
5604
- color: var(--ck-dim);
5605
- }
5606
- .ck-trust-panel__gate {
5607
- font-family: var(--ck-mono);
5608
- font-size: 0.66rem;
5609
- letter-spacing: 0.08em;
5610
- text-transform: uppercase;
5611
- padding: 2px 6px;
5612
- border-radius: 3px;
5613
- background: var(--ck-surface);
5614
- border: 1px solid var(--ck-line);
5615
- color: var(--ck-dim);
5616
- }
5617
- .ck-trust-panel--firm .ck-trust-panel__gate {
5618
- color: var(--ck-success);
5619
- border-color: rgba(45, 212, 168, 0.35);
5620
- }
5621
- .ck-trust-panel__details {
5622
- display: flex;
5623
- flex-wrap: wrap;
5624
- gap: 14px;
5625
- font-family: var(--ck-mono);
5626
- font-size: 0.72rem;
5627
- color: var(--ck-dim);
5626
+ color: var(--ck-text);
5627
+ line-height: 1.5;
5628
5628
  }
5629
- .ck-trust-panel__borderline {
5630
- color: var(--ck-warning);
5629
+ .ck-trust-line__lead {
5630
+ font-weight: 600;
5631
5631
  }
5632
-
5633
- .ck-trust-panel__borderline--ok { color: var(--ck-dim); }
5634
- .ck-trust-panel__borderline--warning { color: var(--ck-warning); }
5635
- .ck-trust-panel__borderline--danger { color: var(--ck-danger); }
5636
-
5637
- .ck-trust-line {
5638
- margin: 10px 0 0;
5639
- font-family: var(--ck-mono);
5640
- font-size: 0.82rem;
5632
+ .ck-trust-line__hint {
5641
5633
  color: var(--ck-dim);
5642
- line-height: 1.55;
5643
5634
  }
5644
- .ck-trust-line > * + * {
5645
- margin-left: 6px;
5635
+ .ck-cal-stat {
5636
+ display: inline-flex;
5637
+ align-items: baseline;
5638
+ gap: 6px;
5646
5639
  }
5647
- .ck-trust-line__label {
5648
- font-size: 0.82rem;
5649
- letter-spacing: 0.08em;
5640
+ .ck-cal-stat__label {
5641
+ font-size: 0.64rem;
5642
+ letter-spacing: 0.09em;
5650
5643
  text-transform: uppercase;
5651
5644
  color: var(--ck-muted);
5652
- white-space: nowrap;
5653
- }
5654
- .ck-trust-line__label svg {
5655
- display: inline-block;
5656
- width: 14px;
5657
- height: 14px;
5658
- vertical-align: middle;
5659
- margin-right: 2px;
5660
- position: relative;
5661
- top: -1px;
5662
- }
5663
- .ck-trust-line__state {
5664
- color: var(--ck-text);
5665
- font-weight: 500;
5666
- }
5667
- .ck-trust-icon {
5668
- display: inline-block;
5669
- width: 11px;
5670
- height: 11px;
5671
- vertical-align: -1px;
5672
- margin-right: 4px;
5673
- color: var(--ck-muted);
5674
- }
5675
- .ck-trust-line__state {
5676
- color: var(--ck-text);
5677
5645
  }
5678
- .ck-trust-line__sep {
5679
- color: var(--ck-line-strong);
5680
- }
5681
- .ck-trust-line__counter {
5682
- font-weight: 600;
5646
+ .ck-trust-line__figure {
5683
5647
  color: var(--ck-accent);
5684
- }
5685
- .ck-trust-line__score {
5686
5648
  font-weight: 600;
5687
- color: var(--ck-success);
5688
5649
  }
5689
- .ck-trust-line--early .ck-trust-line__score,
5690
- .ck-trust-line--provisional .ck-trust-line__score {
5691
- color: var(--ck-accent);
5692
- }
5693
- .ck-trust-line__margin {
5694
- color: var(--ck-dim);
5695
- }
5696
- .ck-trust-line__gate {
5697
- font-size: 0.68rem;
5698
- letter-spacing: 0.06em;
5699
- text-transform: uppercase;
5700
- padding: 1px 6px;
5701
- border-radius: 3px;
5702
- border: 1px solid var(--ck-line);
5703
- color: var(--ck-dim);
5704
- }
5705
- .ck-trust-line--firm .ck-trust-line__gate {
5650
+ .ck-trust-line--firm .ck-trust-line__figure {
5706
5651
  color: var(--ck-success);
5707
- border-color: rgba(45, 212, 168, 0.35);
5708
5652
  }
5709
- .ck-trust-line__hint {
5710
- color: var(--ck-dim);
5711
- }
5712
- .ck-trust-line__link {
5653
+ .ck-trust-line__borderline--ok { color: var(--ck-dim); }
5654
+ .ck-trust-line__borderline--warning { color: var(--ck-warning); }
5655
+ .ck-trust-line__borderline--danger { color: var(--ck-danger); }
5656
+
5657
+ .ck-cal-link {
5658
+ font-family: var(--ck-mono);
5659
+ font-size: 0.78rem;
5660
+ font-weight: 500;
5661
+ letter-spacing: 0.02em;
5713
5662
  color: var(--ck-accent);
5714
5663
  text-decoration: none;
5715
- font-weight: 500;
5716
5664
  white-space: nowrap;
5717
5665
  }
5718
- .ck-trust-line__link:hover,
5719
- .ck-trust-line__link:focus-visible {
5666
+ .ck-cal-link:hover,
5667
+ .ck-cal-link:focus-visible {
5720
5668
  color: var(--ck-accent-hover);
5721
5669
  }
5722
- .ck-trust-line__borderline--ok { color: var(--ck-dim); }
5723
- .ck-trust-line__borderline--warning { color: var(--ck-warning); }
5724
- .ck-trust-line__borderline--danger { color: var(--ck-danger); }
5725
-
5726
- @media (max-width: 640px) {
5727
- .ck-trust-panel {
5728
- display: flex;
5729
- width: 100%;
5730
- box-sizing: border-box;
5731
- }
5732
- .ck-trust-panel__body {
5733
- flex-direction: column;
5734
- align-items: flex-start;
5735
- gap: 4px;
5736
- }
5737
- .ck-trust-panel__hint {
5738
- line-height: 1.4;
5739
- white-space: normal;
5740
- }
5741
- }
5742
-
5743
- .ck-disagreements-table td .ck-meta-copy {
5744
- font-size: 0.78rem;
5670
+ .ck-cal-link--button {
5671
+ background: none;
5672
+ border: 0;
5673
+ padding: 0;
5674
+ cursor: pointer;
5745
5675
  }
5746
- .ck-few-shot-list {
5747
- list-style: decimal;
5748
- padding-left: 1.4rem;
5749
- margin: 0;
5676
+ .ck-cal-foot {
5677
+ margin-top: 14px;
5678
+ padding-top: 12px;
5679
+ border-top: 1px solid var(--ck-line);
5750
5680
  display: flex;
5751
- flex-direction: column;
5752
- gap: 12px;
5681
+ align-items: baseline;
5682
+ justify-content: space-between;
5683
+ gap: 12px 20px;
5684
+ flex-wrap: wrap;
5753
5685
  }
5754
- .ck-few-shot-item {
5755
- padding: 10px 12px;
5756
- background: var(--ck-surface-soft);
5757
- border: 1px solid var(--ck-line);
5758
- border-radius: 6px;
5686
+ .ck-cal-foot__note {
5687
+ color: var(--ck-dim);
5688
+ font-size: 0.86rem;
5759
5689
  }
5760
- .ck-few-shot-item__scores {
5761
- display: flex;
5762
- align-items: center;
5763
- gap: 8px;
5764
- font-family: var(--ck-mono);
5765
- font-size: 0.75rem;
5766
- letter-spacing: 0.04em;
5767
- text-transform: uppercase;
5690
+ .ck-cal-foot__form {
5691
+ display: inline;
5768
5692
  }
5769
5693
 
5770
5694
  .ck-draft-pending {
@@ -5772,47 +5696,6 @@ a.tag-mark {
5772
5696
  background: linear-gradient(180deg, var(--ck-accent-soft), var(--ck-surface));
5773
5697
  }
5774
5698
 
5775
- .ck-suggestion-banner {
5776
- display: inline-flex;
5777
- align-items: center;
5778
- gap: 10px;
5779
- margin-top: 10px;
5780
- padding: 8px 14px;
5781
- background: var(--ck-accent-soft);
5782
- border: 1px solid rgba(6, 182, 212, 0.35);
5783
- border-radius: 6px;
5784
- color: var(--ck-accent);
5785
- font-family: var(--ck-mono);
5786
- font-size: 0.82rem;
5787
- text-decoration: none;
5788
- }
5789
- .ck-suggestion-banner:hover,
5790
- .ck-suggestion-banner:focus-visible {
5791
- border-color: var(--ck-accent);
5792
- }
5793
-
5794
- .ck-metrics-table__trust {
5795
- margin: 4px 0 0;
5796
- font-family: var(--ck-mono);
5797
- font-size: 0.72rem;
5798
- letter-spacing: 0.03em;
5799
- color: var(--ck-dim);
5800
- }
5801
- .ck-metrics-table__trust-label {
5802
- text-transform: uppercase;
5803
- letter-spacing: 0.08em;
5804
- color: var(--ck-muted);
5805
- margin-right: 4px;
5806
- }
5807
- .ck-metrics-table__trust-state {
5808
- color: var(--ck-text);
5809
- }
5810
- .ck-metrics-table__trust-rate {
5811
- font-weight: 600;
5812
- color: var(--ck-success);
5813
- margin-right: 6px;
5814
- }
5815
-
5816
5699
  .ck-calibration__error {
5817
5700
  margin: 8px 0 0;
5818
5701
  padding: 8px 10px;
@@ -5878,30 +5761,9 @@ a.tag-mark {
5878
5761
  0% { background: var(--ck-success); border-color: var(--ck-success); }
5879
5762
  }
5880
5763
 
5881
- .ck-disagreement-list {
5882
- list-style: none;
5883
- padding: 0;
5884
- margin: 12px 0 0;
5885
- display: flex;
5886
- flex-direction: column;
5887
- gap: 12px;
5888
- }
5889
- .ck-disagreement {
5890
- padding: 14px;
5891
- background: var(--ck-surface-soft);
5892
- border: 1px solid var(--ck-line);
5893
- border-radius: 6px;
5894
- display: flex;
5895
- flex-direction: column;
5896
- gap: 8px;
5897
- }
5898
- .ck-disagreement--remembered {
5899
- border-color: rgba(45, 212, 168, 0.35);
5900
- background: rgba(45, 212, 168, 0.04);
5901
- }
5902
-
5903
5764
  .ck-suggestion-banner {
5904
5765
  margin: 0 0 1rem;
5766
+ max-width: 36rem;
5905
5767
  padding: 0.9rem 1rem;
5906
5768
  border: 1px solid rgba(56, 189, 248, 0.35);
5907
5769
  background: rgba(56, 189, 248, 0.05);
@@ -5912,6 +5774,10 @@ a.tag-mark {
5912
5774
  gap: 1rem;
5913
5775
  flex-wrap: wrap;
5914
5776
  }
5777
+ .ck-suggestion-banner__actions .ck-icon-btn {
5778
+ width: 2rem;
5779
+ height: 2rem;
5780
+ }
5915
5781
  .ck-suggestion-banner__body { min-width: 0; flex: 1 1 320px; }
5916
5782
  .ck-suggestion-banner__actions {
5917
5783
  display: inline-flex;
@@ -5960,54 +5826,6 @@ a.tag-mark {
5960
5826
  color: var(--ck-success);
5961
5827
  border-color: rgba(45, 212, 168, 0.45);
5962
5828
  }
5963
- .ck-disagreement__action {
5964
- display: inline-flex;
5965
- align-items: center;
5966
- gap: 8px;
5967
- flex-wrap: wrap;
5968
- }
5969
- .ck-disagreement__head {
5970
- display: flex;
5971
- align-items: center;
5972
- justify-content: space-between;
5973
- gap: 12px;
5974
- flex-wrap: wrap;
5975
- }
5976
- .ck-disagreement__scores {
5977
- display: inline-flex;
5978
- align-items: center;
5979
- gap: 8px;
5980
- flex-wrap: wrap;
5981
- }
5982
- .ck-disagreement__scores-label {
5983
- font-family: var(--ck-mono);
5984
- font-size: 0.7rem;
5985
- letter-spacing: 0.08em;
5986
- text-transform: uppercase;
5987
- color: var(--ck-dim);
5988
- }
5989
- .ck-disagreement__scores-arrow {
5990
- color: var(--ck-dim);
5991
- }
5992
- .ck-disagreement__note {
5993
- margin: 0;
5994
- color: var(--ck-text);
5995
- font-size: 0.92rem;
5996
- line-height: 1.45;
5997
- }
5998
- .ck-disagreement__source {
5999
- margin: 0;
6000
- font-size: 0.78rem;
6001
- }
6002
- .ck-disagreement__source-link {
6003
- color: var(--ck-accent);
6004
- text-decoration: none;
6005
- font-weight: 500;
6006
- }
6007
- .ck-disagreement__source-link:hover,
6008
- .ck-disagreement__source-link:focus-visible {
6009
- color: var(--ck-accent-hover);
6010
- }
6011
5829
 
6012
5830
  .ck-starter-row {
6013
5831
  margin-top: 2rem;
@@ -6029,13 +5847,16 @@ a.tag-mark {
6029
5847
  }
6030
5848
  .ck-starter-grid {
6031
5849
  display: grid;
6032
- grid-template-columns: repeat(4, 1fr);
5850
+ grid-template-columns: repeat(5, 1fr);
6033
5851
  gap: 12px;
6034
5852
  }
6035
- @media (max-width: 1000px) {
5853
+ @media (max-width: 1100px) {
5854
+ .ck-starter-grid { grid-template-columns: repeat(3, 1fr); }
5855
+ }
5856
+ @media (max-width: 700px) {
6036
5857
  .ck-starter-grid { grid-template-columns: repeat(2, 1fr); }
6037
5858
  }
6038
- @media (max-width: 600px) {
5859
+ @media (max-width: 500px) {
6039
5860
  .ck-starter-grid { grid-template-columns: 1fr; }
6040
5861
  }
6041
5862
  .ck-starter-card {
@@ -3,26 +3,36 @@ module CompletionKit
3
3
  module V1
4
4
  class BaseController < ActionController::API
5
5
  rate_limit to: CompletionKit.config.api_rate_limit, within: 1.minute,
6
- with: -> { render json: {error: "Rate limit exceeded"}, status: :too_many_requests }
6
+ with: -> { render_error("Rate limit exceeded", status: :too_many_requests) }
7
7
  before_action :authenticate_api!
8
8
 
9
9
  private
10
10
 
11
+ def render_error(message, status:, details: nil)
12
+ payload = { error: message }
13
+ payload[:details] = details if details.present?
14
+ render json: payload, status: status
15
+ end
16
+
17
+ def render_validation_errors(record, status: :unprocessable_entity)
18
+ render_error("Validation failed", status: status, details: record.errors.as_json)
19
+ end
20
+
11
21
  def authenticate_api!
12
22
  token = CompletionKit.config.api_token
13
23
  unless token
14
- render json: {error: "API token not configured"}, status: :unauthorized
24
+ render_error("API token not configured", status: :unauthorized)
15
25
  return
16
26
  end
17
27
 
18
28
  provided = request.headers["Authorization"]&.match(/\ABearer (.+)\z/)&.[](1)
19
29
  unless provided && ActiveSupport::SecurityUtils.secure_compare(provided, token)
20
- render json: {error: "Unauthorized"}, status: :unauthorized
30
+ render_error("Unauthorized", status: :unauthorized)
21
31
  end
22
32
  end
23
33
 
24
34
  def not_found
25
- render json: {error: "Record not found"}, status: :not_found
35
+ render_error("Record not found", status: :not_found)
26
36
  end
27
37
 
28
38
  PAGINATION_DEFAULT_LIMIT = 50
@@ -30,7 +30,7 @@ module CompletionKit
30
30
  if calibration.save
31
31
  render json: calibration, status: calibration.previously_new_record? ? :created : :ok
32
32
  else
33
- render json: { errors: calibration.errors }, status: :unprocessable_entity
33
+ render_validation_errors(calibration)
34
34
  end
35
35
  end
36
36
 
@@ -42,7 +42,7 @@ module CompletionKit
42
42
  private
43
43
 
44
44
  def ensure_calibration_enabled
45
- render(json: { error: "Calibration disabled" }, status: :not_found) unless CompletionKit.config.judge_calibration_enabled
45
+ render_error("Calibration disabled", status: :not_found) unless CompletionKit.config.judge_calibration_enabled
46
46
  end
47
47
 
48
48
  def set_nested_scope
@@ -19,7 +19,7 @@ module CompletionKit
19
19
  if dataset.save
20
20
  render json: dataset, status: :created
21
21
  else
22
- render json: {errors: dataset.errors}, status: :unprocessable_entity
22
+ render_validation_errors(dataset)
23
23
  end
24
24
  end
25
25
 
@@ -27,7 +27,7 @@ module CompletionKit
27
27
  if @dataset.update(dataset_params)
28
28
  render json: @dataset
29
29
  else
30
- render json: {errors: @dataset.errors}, status: :unprocessable_entity
30
+ render_validation_errors(@dataset)
31
31
  end
32
32
  end
33
33