@thinkai/tai-api-contract 2.170.0 → 2.172.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.
@@ -1,7 +1,7 @@
1
1
  openapi: 3.0.3
2
2
  info:
3
3
  title: ThinkAI API
4
- version: 2.170.0
4
+ version: 2.172.0
5
5
  description: >
6
6
  Contract surface for the AI Driven SDLC backend used by ThinkAI.
7
7
  Workspace-scoped routes use `/workspaces/{workspaceId}/...`.
@@ -92,6 +92,12 @@ tags:
92
92
  classified test-file inventory (unit, integration, acceptance/BDD, contract, E2E)
93
93
  with count-based presence and advisory 70/20/10 shape. Distinct from Agentic
94
94
  Foundation readiness `/readiness/test-pyramid*` (signal-inclusive presence).
95
+ - name: Evals
96
+ description: >
97
+ Workspace prompt/model eval suites (`/evals/*`) — authored golden cases with
98
+ deterministic expected-signal scoring, async runs (never scored on the request
99
+ path), and an Insights surface for regressions and token efficiency. Distinct
100
+ from AI Usage & Spend ingest and Agentic Foundation Token Efficiency (rubric I).
95
101
 
96
102
  paths:
97
103
  /admin/users/{userId}:
@@ -412,6 +418,162 @@ paths:
412
418
  error: Forbidden
413
419
  code: forbidden
414
420
 
421
+ /admin/assessment-manifest-validation:
422
+ post:
423
+ tags: [PlatformAdmin]
424
+ summary: Validate an assessment manifest before export
425
+ operationId: runAssessmentManifestValidation
426
+ description: >
427
+ Runs the fail-closed manifest check for one sold assessment. The server
428
+ ignores `manifest.validation` and `manifest.watermark` from the client.
429
+ `buyerDeliverable` is true only when the result is validated and
430
+ `shareMode` is internal. An external share-safe result can be validated
431
+ and is never the buyer file. Unset or exceeded tolerances fail. No
432
+ numeric tolerance is assumed. GitLab and Bitbucket fixtures are not part
433
+ of this operation.
434
+
435
+ **Authorization:** Bearer JWT required. Caller email must appear in `PLATFORM_ADMIN_EMAILS`.
436
+ requestBody:
437
+ required: true
438
+ content:
439
+ application/json:
440
+ schema:
441
+ type: object
442
+ required:
443
+ - manifest
444
+ - workspaceId
445
+ - expectedWorkspaceId
446
+ - expectedRepositoryIds
447
+ - soldWindowComplete
448
+ - premiumAiAssessable
449
+ - namedPersonSectionIds
450
+ - tolerances
451
+ properties:
452
+ manifest:
453
+ type: object
454
+ required:
455
+ - offerId
456
+ - dictionaryVersion
457
+ - validation
458
+ - shareMode
459
+ - watermark
460
+ - scope
461
+ - windows
462
+ - sources
463
+ - consent
464
+ - sections
465
+ properties:
466
+ offerId:
467
+ type: string
468
+ enum: [engineering_readiness_baseline, agentic_ai_roi]
469
+ dictionaryVersion:
470
+ type: string
471
+ validation:
472
+ type: string
473
+ enum: [validated, not_validated]
474
+ shareMode:
475
+ type: string
476
+ enum: [internal, external]
477
+ watermark:
478
+ type: string
479
+ nullable: true
480
+ enum: ["NOT VALIDATED", "SAMPLE · SYNTHETIC DATA"]
481
+ scope:
482
+ type: object
483
+ windows:
484
+ type: object
485
+ sources:
486
+ type: array
487
+ items:
488
+ type: object
489
+ consent:
490
+ type: object
491
+ sections:
492
+ type: array
493
+ items:
494
+ type: object
495
+ workspaceId:
496
+ type: string
497
+ expectedWorkspaceId:
498
+ type: string
499
+ expectedRepositoryIds:
500
+ type: array
501
+ items:
502
+ type: string
503
+ soldWindowComplete:
504
+ type: boolean
505
+ premiumAiAssessable:
506
+ type: boolean
507
+ namedPersonSectionIds:
508
+ type: array
509
+ items:
510
+ type: string
511
+ tolerances:
512
+ type: array
513
+ items:
514
+ type: object
515
+ required: [id, status]
516
+ properties:
517
+ id:
518
+ type: string
519
+ status:
520
+ type: string
521
+ enum: [unset, exceeded, within]
522
+ responses:
523
+ "200":
524
+ description: Validation result. Client validation and watermark inputs are ignored.
525
+ content:
526
+ application/json:
527
+ schema:
528
+ type: object
529
+ required: [buyerDeliverable, validation, watermark, reasons, contentHash]
530
+ properties:
531
+ buyerDeliverable:
532
+ type: boolean
533
+ validation:
534
+ type: string
535
+ enum: [validated, not_validated]
536
+ watermark:
537
+ type: string
538
+ nullable: true
539
+ enum: ["NOT VALIDATED"]
540
+ reasons:
541
+ type: array
542
+ items:
543
+ type: object
544
+ required: [code, message]
545
+ properties:
546
+ code:
547
+ type: string
548
+ message:
549
+ type: string
550
+ contentHash:
551
+ type: string
552
+ "400":
553
+ description: Body failed validation.
554
+ content:
555
+ application/json:
556
+ schema:
557
+ $ref: "#/components/schemas/ErrorMessageDto"
558
+ example:
559
+ error: manifest.offerId is not a known assessment offer
560
+ code: invalid_body
561
+ "401":
562
+ description: Missing or invalid JWT.
563
+ content:
564
+ application/json:
565
+ schema:
566
+ $ref: "#/components/schemas/ErrorMessageDto"
567
+ "403":
568
+ description: Caller is not a platform admin.
569
+ content:
570
+ application/json:
571
+ schema:
572
+ $ref: "#/components/schemas/ErrorMessageDto"
573
+ example:
574
+ error: Forbidden
575
+ code: forbidden
576
+
415
577
  /admin/readiness/token-usage:
416
578
  get:
417
579
  tags: [PlatformAdmin]
@@ -11783,189 +11945,557 @@ paths:
11783
11945
  "403":
11784
11946
  $ref: "#/components/responses/Forbidden"
11785
11947
 
11786
- components:
11787
- securitySchemes:
11788
- bearerAuth:
11789
- type: http
11790
- scheme: bearer
11791
- bearerFormat: JWT
11792
- description: Supabase access token (`Authorization` header).
11793
-
11794
- parameters:
11795
- WorkspaceId:
11796
- name: workspaceId
11797
- in: path
11798
- required: true
11799
- schema:
11800
- type: string
11801
- RepoId:
11802
- name: repoId
11803
- in: path
11804
- required: true
11805
- schema:
11806
- type: string
11807
- format: uuid
11808
- ProviderSlug:
11809
- name: providerSlug
11810
- in: path
11811
- required: true
11812
- description: >
11813
- Provider repository slug in `owner/repo` form (GitHub). Used for shareable public URLs;
11814
- resolves to the same row as `repoId` UUID internally.
11815
- schema:
11816
- type: string
11817
- minLength: 1
11818
- maxLength: 512
11819
- pattern: "^[^/]+/[^/]+$"
11820
- example: thinkai-llc/thinkai-platform-backend
11821
- ProjectId:
11822
- name: projectId
11823
- in: path
11824
- required: true
11825
- schema:
11826
- type: string
11827
- NotificationId:
11828
- name: id
11829
- in: path
11830
- required: true
11831
- schema:
11832
- type: string
11833
- WorkspaceMemberId:
11834
- name: memberId
11835
- in: path
11836
- required: true
11837
- schema:
11838
- type: string
11839
- format: uuid
11840
- description: Workspace member user id (`tai_users.id`).
11841
- WorkspaceInvitationToken:
11842
- name: token
11843
- in: path
11844
- required: true
11845
- schema:
11846
- type: string
11847
- minLength: 32
11848
- description: >
11849
- Opaque workspace invitation token from the emailed accept link. Only its SHA-256
11850
- hash is stored server-side; the plaintext is shown exactly once, in the email.
11851
- PrivacyRequestId:
11852
- name: requestId
11853
- in: path
11854
- required: true
11855
- schema:
11856
- type: string
11857
- format: uuid
11858
- description: Privacy request id (`tai_privacy_requests.id`).
11859
- FixId:
11860
- name: fixId
11861
- in: path
11862
- required: true
11863
- schema:
11864
- type: string
11865
- format: uuid
11866
- ReadinessIssueId:
11867
- name: issueId
11868
- in: path
11869
- required: true
11870
- schema:
11871
- type: string
11872
- format: uuid
11873
- description: Readiness issue id (`tai_workspace_repo_issues.id`).
11874
- InsightsProductivityRangeId:
11875
- name: rangeId
11876
- in: query
11948
+ /workspaces/{workspaceId}/evals/suites:
11949
+ get:
11950
+ tags: [Evals]
11951
+ summary: List eval suites for a workspace
11877
11952
  description: >
11878
- Productivity insights time range. Daily windows: `7d`, `30d`, `90d`, `180d`, or custom
11879
- `cr:YYYY-MM-DD:YYYY-MM-DD`. Weekly legacy: `4w`, `8w`, `q` (12 weeks), `12w`, `16w`.
11880
- Omit when using explicit `from`/`to` day bounds.
11881
- schema:
11882
- type: string
11883
- default: 4w
11884
- InsightsProductivityFrom:
11885
- name: from
11886
- in: query
11953
+ Returns the latest version of each eval suite in the workspace (max 50 suites).
11954
+ Requires workspace membership (`requireWorkspaceMember`). Empty workspace →
11955
+ `{ "suites": [] }`.
11956
+ operationId: listEvalSuites
11957
+ x-test-coverage-skip: contract-only; HTTP/store coverage lands with evals-storage-api
11958
+ parameters:
11959
+ - $ref: "#/components/parameters/WorkspaceId"
11960
+ responses:
11961
+ "200":
11962
+ description: Suite list (latest version per suite)
11963
+ content:
11964
+ application/json:
11965
+ schema:
11966
+ $ref: "#/components/schemas/EvalSuiteListDto"
11967
+ example:
11968
+ suites: []
11969
+ "401":
11970
+ $ref: "#/components/responses/Unauthorized"
11971
+ "403":
11972
+ $ref: "#/components/responses/Forbidden"
11973
+ "404":
11974
+ description: Workspace not found
11975
+ content:
11976
+ application/json:
11977
+ schema:
11978
+ $ref: "#/components/schemas/ErrorMessageDto"
11979
+ post:
11980
+ tags: [Evals]
11981
+ summary: Create an eval suite
11887
11982
  description: >
11888
- Inclusive start of a daily window (`YYYY-MM-DD`). When set with `to`, overrides `rangeId`
11889
- for day-mode responses (max 180 days).
11890
- schema:
11891
- type: string
11892
- format: date
11893
- InsightsProductivityTo:
11894
- name: to
11895
- in: query
11983
+ Creates a suite at `version: 1`. Requires workspace editor or admin
11984
+ (`requireWorkspaceEditor`). Rejects when both `target.promptBody` is empty
11985
+ and model fields are missing; when `cases` is empty (`400`
11986
+ `eval_suite_cases_required`); or when the workspace already has 50 suites.
11987
+ Each case must include at least one expected signal.
11988
+ operationId: createEvalSuite
11989
+ x-test-coverage-skip: contract-only; HTTP/store coverage lands with evals-storage-api
11990
+ parameters:
11991
+ - $ref: "#/components/parameters/WorkspaceId"
11992
+ requestBody:
11993
+ required: true
11994
+ content:
11995
+ application/json:
11996
+ schema:
11997
+ $ref: "#/components/schemas/CreateEvalSuiteBodyDto"
11998
+ example:
11999
+ name: Greeting quality
12000
+ description: Fixture-backed smoke suite for the support greeting prompt
12001
+ target:
12002
+ promptBody: "You are a support agent. Greet the user by name."
12003
+ promptKey: support-greeting
12004
+ provider: cursor
12005
+ modelName: gpt-4.1-mini
12006
+ cases:
12007
+ - id: case-hello
12008
+ name: Hello Alice
12009
+ input: '{"name":"Alice"}'
12010
+ fixtureCompletion: "Hello Alice, how can I help you today?"
12011
+ expectedSignals:
12012
+ - id: sig-contains-hello
12013
+ kind: contains
12014
+ value: "Hello Alice"
12015
+ - id: sig-not-sorry
12016
+ kind: not_contains
12017
+ value: "I cannot"
12018
+ responses:
12019
+ "201":
12020
+ description: Suite created
12021
+ content:
12022
+ application/json:
12023
+ schema:
12024
+ $ref: "#/components/schemas/EvalSuiteDto"
12025
+ "400":
12026
+ description: >
12027
+ Validation failed — empty cases (`eval_suite_cases_required`), missing
12028
+ target (prompt and model), invalid name/description lengths, case/signal
12029
+ bounds, or malformed body.
12030
+ content:
12031
+ application/json:
12032
+ schema:
12033
+ $ref: "#/components/schemas/ErrorMessageDto"
12034
+ examples:
12035
+ cases_required:
12036
+ value:
12037
+ error: At least one case is required
12038
+ code: eval_suite_cases_required
12039
+ target_required:
12040
+ value:
12041
+ error: Suite target requires promptBody or provider+modelName
12042
+ code: eval_suite_target_required
12043
+ "401":
12044
+ $ref: "#/components/responses/Unauthorized"
12045
+ "403":
12046
+ description: Authenticated but not a workspace editor/admin
12047
+ content:
12048
+ application/json:
12049
+ schema:
12050
+ $ref: "#/components/schemas/ErrorMessageDto"
12051
+ example:
12052
+ error: Workspace editor role required
12053
+ code: workspace_editor_required
12054
+ "404":
12055
+ description: Workspace not found
12056
+ content:
12057
+ application/json:
12058
+ schema:
12059
+ $ref: "#/components/schemas/ErrorMessageDto"
12060
+ "409":
12061
+ description: Workspace already has the maximum of 50 suites
12062
+ content:
12063
+ application/json:
12064
+ schema:
12065
+ $ref: "#/components/schemas/ErrorMessageDto"
12066
+ example:
12067
+ error: Maximum of 50 eval suites per workspace
12068
+ code: eval_suite_limit_reached
12069
+
12070
+ /workspaces/{workspaceId}/evals/suites/{suiteId}:
12071
+ get:
12072
+ tags: [Evals]
12073
+ summary: Get an eval suite (latest version)
11896
12074
  description: >
11897
- Inclusive end of a daily window (`YYYY-MM-DD`). When set with `from`, overrides `rangeId`
11898
- for day-mode responses (max 180 days).
12075
+ Returns the latest version of the suite. Historical versions are retained for
12076
+ runs via `suiteVersion` + snapshot on each run; this endpoint does not expose
12077
+ prior versions. Requires workspace membership.
12078
+ operationId: getEvalSuite
12079
+ x-test-coverage-skip: contract-only; HTTP/store coverage lands with evals-storage-api
12080
+ parameters:
12081
+ - $ref: "#/components/parameters/WorkspaceId"
12082
+ - $ref: "#/components/parameters/EvalSuiteId"
12083
+ responses:
12084
+ "200":
12085
+ description: Suite (latest version)
12086
+ content:
12087
+ application/json:
12088
+ schema:
12089
+ $ref: "#/components/schemas/EvalSuiteDto"
12090
+ "401":
12091
+ $ref: "#/components/responses/Unauthorized"
12092
+ "403":
12093
+ $ref: "#/components/responses/Forbidden"
12094
+ "404":
12095
+ description: Workspace or suite not found
12096
+ content:
12097
+ application/json:
12098
+ schema:
12099
+ $ref: "#/components/schemas/ErrorMessageDto"
12100
+ put:
12101
+ tags: [Evals]
12102
+ summary: Update an eval suite
12103
+ description: >
12104
+ Replaces mutable suite fields. Requires workspace editor or admin.
12105
+ Changing `target`, `cases`, or `promptBody` increments `version` by 1 and
12106
+ keeps prior versions immutable for historical runs. Cosmetic
12107
+ name/description-only updates do not bump `version`. Same validation rules
12108
+ as create (cases required, target required, bounds).
12109
+ operationId: updateEvalSuite
12110
+ x-test-coverage-skip: contract-only; HTTP/store coverage lands with evals-storage-api
12111
+ parameters:
12112
+ - $ref: "#/components/parameters/WorkspaceId"
12113
+ - $ref: "#/components/parameters/EvalSuiteId"
12114
+ requestBody:
12115
+ required: true
12116
+ content:
12117
+ application/json:
12118
+ schema:
12119
+ $ref: "#/components/schemas/UpdateEvalSuiteBodyDto"
12120
+ responses:
12121
+ "200":
12122
+ description: Suite updated (possibly with bumped version)
12123
+ content:
12124
+ application/json:
12125
+ schema:
12126
+ $ref: "#/components/schemas/EvalSuiteDto"
12127
+ "400":
12128
+ description: Validation failed (same codes as create)
12129
+ content:
12130
+ application/json:
12131
+ schema:
12132
+ $ref: "#/components/schemas/ErrorMessageDto"
12133
+ "401":
12134
+ $ref: "#/components/responses/Unauthorized"
12135
+ "403":
12136
+ description: Authenticated but not a workspace editor/admin
12137
+ content:
12138
+ application/json:
12139
+ schema:
12140
+ $ref: "#/components/schemas/ErrorMessageDto"
12141
+ example:
12142
+ error: Workspace editor role required
12143
+ code: workspace_editor_required
12144
+ "404":
12145
+ description: Workspace or suite not found
12146
+ content:
12147
+ application/json:
12148
+ schema:
12149
+ $ref: "#/components/schemas/ErrorMessageDto"
12150
+
12151
+ /workspaces/{workspaceId}/evals/suites/{suiteId}/runs:
12152
+ get:
12153
+ tags: [Evals]
12154
+ summary: List recent eval runs for a suite
12155
+ description: >
12156
+ Returns the last 50 runs for the suite (newest first). Empty → `{ "runs": [] }`.
12157
+ Requires workspace membership. Does not trigger scoring.
12158
+ operationId: listEvalRuns
12159
+ x-test-coverage-skip: contract-only; HTTP/store coverage lands with evals-storage-api
12160
+ parameters:
12161
+ - $ref: "#/components/parameters/WorkspaceId"
12162
+ - $ref: "#/components/parameters/EvalSuiteId"
12163
+ responses:
12164
+ "200":
12165
+ description: Run history (max 50)
12166
+ content:
12167
+ application/json:
12168
+ schema:
12169
+ $ref: "#/components/schemas/EvalRunListDto"
12170
+ example:
12171
+ runs: []
12172
+ "401":
12173
+ $ref: "#/components/responses/Unauthorized"
12174
+ "403":
12175
+ $ref: "#/components/responses/Forbidden"
12176
+ "404":
12177
+ description: Workspace or suite not found
12178
+ content:
12179
+ application/json:
12180
+ schema:
12181
+ $ref: "#/components/schemas/ErrorMessageDto"
12182
+ post:
12183
+ tags: [Evals]
12184
+ summary: Enqueue an eval suite run
12185
+ description: >
12186
+ Enqueues an async eval run. Returns `202` with `{ runId, status: "queued" }`.
12187
+ Never scores on the request path — a worker claims the run, uses
12188
+ `fixtureCompletion` when present (or live completion when provider credentials
12189
+ exist), applies deterministic expected-signal scoring, and persists results.
12190
+ Requires workspace editor or admin. At most one active (`queued`|`running`)
12191
+ run per suite; a second POST returns `409` `eval_run_in_progress`.
12192
+ operationId: enqueueEvalRun
12193
+ x-test-coverage-skip: contract-only; HTTP/store coverage lands with evals-storage-api
12194
+ parameters:
12195
+ - $ref: "#/components/parameters/WorkspaceId"
12196
+ - $ref: "#/components/parameters/EvalSuiteId"
12197
+ responses:
12198
+ "202":
12199
+ description: Run queued
12200
+ content:
12201
+ application/json:
12202
+ schema:
12203
+ $ref: "#/components/schemas/EvalRunEnqueueResponseDto"
12204
+ example:
12205
+ runId: "22222222-2222-4222-8222-222222222222"
12206
+ status: queued
12207
+ "401":
12208
+ $ref: "#/components/responses/Unauthorized"
12209
+ "403":
12210
+ description: Authenticated but not a workspace editor/admin
12211
+ content:
12212
+ application/json:
12213
+ schema:
12214
+ $ref: "#/components/schemas/ErrorMessageDto"
12215
+ example:
12216
+ error: Workspace editor role required
12217
+ code: workspace_editor_required
12218
+ "404":
12219
+ description: Workspace or suite not found
12220
+ content:
12221
+ application/json:
12222
+ schema:
12223
+ $ref: "#/components/schemas/ErrorMessageDto"
12224
+ "409":
12225
+ description: An active queued or running eval already exists for this suite
12226
+ content:
12227
+ application/json:
12228
+ schema:
12229
+ $ref: "#/components/schemas/ErrorMessageDto"
12230
+ example:
12231
+ error: An eval run is already in progress for this suite
12232
+ code: eval_run_in_progress
12233
+
12234
+ /workspaces/{workspaceId}/evals/suites/{suiteId}/runs/{runId}:
12235
+ get:
12236
+ tags: [Evals]
12237
+ summary: Get an eval run with case results
12238
+ description: >
12239
+ Returns persisted run status and case results. While `queued` or `running`,
12240
+ `caseResults` may be empty and `score` null. Requires workspace membership.
12241
+ Does not trigger scoring.
12242
+ operationId: getEvalRun
12243
+ x-test-coverage-skip: contract-only; HTTP/store coverage lands with evals-storage-api
12244
+ parameters:
12245
+ - $ref: "#/components/parameters/WorkspaceId"
12246
+ - $ref: "#/components/parameters/EvalSuiteId"
12247
+ - $ref: "#/components/parameters/EvalRunId"
12248
+ responses:
12249
+ "200":
12250
+ description: Run detail
12251
+ content:
12252
+ application/json:
12253
+ schema:
12254
+ $ref: "#/components/schemas/EvalRunDto"
12255
+ "401":
12256
+ $ref: "#/components/responses/Unauthorized"
12257
+ "403":
12258
+ $ref: "#/components/responses/Forbidden"
12259
+ "404":
12260
+ description: Workspace, suite, or run not found
12261
+ content:
12262
+ application/json:
12263
+ schema:
12264
+ $ref: "#/components/schemas/ErrorMessageDto"
12265
+
12266
+ /workspaces/{workspaceId}/evals/insights:
12267
+ get:
12268
+ tags: [Evals]
12269
+ summary: Eval insights (regressions, tips, efficiency, model comparison)
12270
+ description: >
12271
+ Workspace-level Insights for prompt/model evals. Computes regressions when
12272
+ prior score − current score ≥ 0.10 on the same suiteId+suiteVersion case set
12273
+ (or suite score drop ≥ 0.10); prompt tips from failed signal notes / case
12274
+ names; token efficiency averages over successful cases in the last succeeded
12275
+ run per suite; and model comparison rollups. No succeeded runs → empty arrays
12276
+ and null `tokenEfficiency`. Requires workspace membership. Distinct from
12277
+ `/insights-recommendations` and AI Usage & Spend.
12278
+ operationId: getEvalInsights
12279
+ x-test-coverage-skip: contract-only; HTTP/store coverage lands with evals-storage-api
12280
+ parameters:
12281
+ - $ref: "#/components/parameters/WorkspaceId"
12282
+ responses:
12283
+ "200":
12284
+ description: Insights payload
12285
+ content:
12286
+ application/json:
12287
+ schema:
12288
+ $ref: "#/components/schemas/EvalInsightsDto"
12289
+ "401":
12290
+ $ref: "#/components/responses/Unauthorized"
12291
+ "403":
12292
+ $ref: "#/components/responses/Forbidden"
12293
+ "404":
12294
+ description: Workspace not found
12295
+ content:
12296
+ application/json:
12297
+ schema:
12298
+ $ref: "#/components/schemas/ErrorMessageDto"
12299
+
12300
+ components:
12301
+ securitySchemes:
12302
+ bearerAuth:
12303
+ type: http
12304
+ scheme: bearer
12305
+ bearerFormat: JWT
12306
+ description: Supabase access token (`Authorization` header).
12307
+
12308
+ parameters:
12309
+ WorkspaceId:
12310
+ name: workspaceId
12311
+ in: path
12312
+ required: true
11899
12313
  schema:
11900
12314
  type: string
11901
- format: date
11902
- InsightsSdlcRangeId:
11903
- name: rangeId
11904
- in: query
11905
- description: >
11906
- Day-level Measure window. Presets: `7d`, `30d`, `90d`, `180d`. Custom inclusive
11907
- calendar range: `cr:YYYY-MM-DD:YYYY-MM-DD` (max span 180 days).
12315
+ EvalSuiteId:
12316
+ name: suiteId
12317
+ in: path
12318
+ required: true
11908
12319
  schema:
11909
12320
  type: string
11910
- default: 30d
11911
- example: 30d
11912
- InsightsDepartmentFilter:
11913
- name: department
11914
- in: query
11915
- description: >
11916
- Department filter; send `All departments` to include every department. Scoped using
11917
- imported `thinkai_org_structure` members when present, otherwise SPA org chart
11918
- `department` nodes and their descendant teams. When neither source defines the
11919
- requested department, insights return no scoped teams or contributors (not org-wide
11920
- data).
12321
+ format: uuid
12322
+ description: Eval suite id (`tai_workspace_eval_suites.id`).
12323
+ EvalRunId:
12324
+ name: runId
12325
+ in: path
12326
+ required: true
11921
12327
  schema:
11922
12328
  type: string
11923
- default: All departments
11924
- InsightsRecommendationsDepartments:
11925
- name: departments
11926
- in: query
11927
- description: >
11928
- Org-chart department ids (repeat param or comma-separated). Empty/omitted = all departments.
12329
+ format: uuid
12330
+ description: Eval run id (`tai_workspace_eval_runs.id`).
12331
+ RepoId:
12332
+ name: repoId
12333
+ in: path
12334
+ required: true
11929
12335
  schema:
11930
- type: array
11931
- items:
11932
- type: string
11933
- style: form
11934
- explode: true
11935
- InsightsRecommendationsTeams:
11936
- name: teams
11937
- in: query
12336
+ type: string
12337
+ format: uuid
12338
+ ProviderSlug:
12339
+ name: providerSlug
12340
+ in: path
12341
+ required: true
11938
12342
  description: >
11939
- Org-chart team ids (repeat param or comma-separated). Empty/omitted = all teams in department scope.
12343
+ Provider repository slug in `owner/repo` form (GitHub). Used for shareable public URLs;
12344
+ resolves to the same row as `repoId` UUID internally.
11940
12345
  schema:
11941
- type: array
11942
- items:
11943
- type: string
11944
- style: form
11945
- explode: true
11946
- InsightsRecommendationsDateFrom:
11947
- name: dateFrom
11948
- in: query
11949
- description: >
11950
- Inclusive window start (`YYYY-MM-DD`). Required with `dateTo`. Maps to Measure day-mode
11951
- custom range (`from`/`to`). Max span 180 days.
12346
+ type: string
12347
+ minLength: 1
12348
+ maxLength: 512
12349
+ pattern: "^[^/]+/[^/]+$"
12350
+ example: thinkai-llc/thinkai-platform-backend
12351
+ ProjectId:
12352
+ name: projectId
12353
+ in: path
11952
12354
  required: true
11953
12355
  schema:
11954
12356
  type: string
11955
- format: date
11956
- InsightsRecommendationsDateTo:
11957
- name: dateTo
11958
- in: query
11959
- description: Inclusive window end (`YYYY-MM-DD`). Required with `dateFrom`.
12357
+ NotificationId:
12358
+ name: id
12359
+ in: path
11960
12360
  required: true
11961
12361
  schema:
11962
12362
  type: string
11963
- format: date
11964
- InsightsRecommendationsProvider:
11965
- name: provider
11966
- in: query
12363
+ WorkspaceMemberId:
12364
+ name: memberId
12365
+ in: path
12366
+ required: true
12367
+ schema:
12368
+ type: string
12369
+ format: uuid
12370
+ description: Workspace member user id (`tai_users.id`).
12371
+ WorkspaceInvitationToken:
12372
+ name: token
12373
+ in: path
12374
+ required: true
12375
+ schema:
12376
+ type: string
12377
+ minLength: 32
11967
12378
  description: >
11968
- AI provider ids (e.g. `cursor`, `copilot`). Empty/omitted = all configured providers.
12379
+ Opaque workspace invitation token from the emailed accept link. Only its SHA-256
12380
+ hash is stored server-side; the plaintext is shown exactly once, in the email.
12381
+ PrivacyRequestId:
12382
+ name: requestId
12383
+ in: path
12384
+ required: true
12385
+ schema:
12386
+ type: string
12387
+ format: uuid
12388
+ description: Privacy request id (`tai_privacy_requests.id`).
12389
+ FixId:
12390
+ name: fixId
12391
+ in: path
12392
+ required: true
12393
+ schema:
12394
+ type: string
12395
+ format: uuid
12396
+ ReadinessIssueId:
12397
+ name: issueId
12398
+ in: path
12399
+ required: true
12400
+ schema:
12401
+ type: string
12402
+ format: uuid
12403
+ description: Readiness issue id (`tai_workspace_repo_issues.id`).
12404
+ InsightsProductivityRangeId:
12405
+ name: rangeId
12406
+ in: query
12407
+ description: >
12408
+ Productivity insights time range. Daily windows: `7d`, `30d`, `90d`, `180d`, or custom
12409
+ `cr:YYYY-MM-DD:YYYY-MM-DD`. Weekly legacy: `4w`, `8w`, `q` (12 weeks), `12w`, `16w`.
12410
+ Omit when using explicit `from`/`to` day bounds.
12411
+ schema:
12412
+ type: string
12413
+ default: 4w
12414
+ InsightsProductivityFrom:
12415
+ name: from
12416
+ in: query
12417
+ description: >
12418
+ Inclusive start of a daily window (`YYYY-MM-DD`). When set with `to`, overrides `rangeId`
12419
+ for day-mode responses (max 180 days).
12420
+ schema:
12421
+ type: string
12422
+ format: date
12423
+ InsightsProductivityTo:
12424
+ name: to
12425
+ in: query
12426
+ description: >
12427
+ Inclusive end of a daily window (`YYYY-MM-DD`). When set with `from`, overrides `rangeId`
12428
+ for day-mode responses (max 180 days).
12429
+ schema:
12430
+ type: string
12431
+ format: date
12432
+ InsightsSdlcRangeId:
12433
+ name: rangeId
12434
+ in: query
12435
+ description: >
12436
+ Day-level Measure window. Presets: `7d`, `30d`, `90d`, `180d`. Custom inclusive
12437
+ calendar range: `cr:YYYY-MM-DD:YYYY-MM-DD` (max span 180 days).
12438
+ schema:
12439
+ type: string
12440
+ default: 30d
12441
+ example: 30d
12442
+ InsightsDepartmentFilter:
12443
+ name: department
12444
+ in: query
12445
+ description: >
12446
+ Department filter; send `All departments` to include every department. Scoped using
12447
+ imported `thinkai_org_structure` members when present, otherwise SPA org chart
12448
+ `department` nodes and their descendant teams. When neither source defines the
12449
+ requested department, insights return no scoped teams or contributors (not org-wide
12450
+ data).
12451
+ schema:
12452
+ type: string
12453
+ default: All departments
12454
+ InsightsRecommendationsDepartments:
12455
+ name: departments
12456
+ in: query
12457
+ description: >
12458
+ Org-chart department ids (repeat param or comma-separated). Empty/omitted = all departments.
12459
+ schema:
12460
+ type: array
12461
+ items:
12462
+ type: string
12463
+ style: form
12464
+ explode: true
12465
+ InsightsRecommendationsTeams:
12466
+ name: teams
12467
+ in: query
12468
+ description: >
12469
+ Org-chart team ids (repeat param or comma-separated). Empty/omitted = all teams in department scope.
12470
+ schema:
12471
+ type: array
12472
+ items:
12473
+ type: string
12474
+ style: form
12475
+ explode: true
12476
+ InsightsRecommendationsDateFrom:
12477
+ name: dateFrom
12478
+ in: query
12479
+ description: >
12480
+ Inclusive window start (`YYYY-MM-DD`). Required with `dateTo`. Maps to Measure day-mode
12481
+ custom range (`from`/`to`). Max span 180 days.
12482
+ required: true
12483
+ schema:
12484
+ type: string
12485
+ format: date
12486
+ InsightsRecommendationsDateTo:
12487
+ name: dateTo
12488
+ in: query
12489
+ description: Inclusive window end (`YYYY-MM-DD`). Required with `dateFrom`.
12490
+ required: true
12491
+ schema:
12492
+ type: string
12493
+ format: date
12494
+ InsightsRecommendationsProvider:
12495
+ name: provider
12496
+ in: query
12497
+ description: >
12498
+ AI provider ids (e.g. `cursor`, `copilot`). Empty/omitted = all configured providers.
11969
12499
  schema:
11970
12500
  type: array
11971
12501
  items:
@@ -24494,842 +25024,1378 @@ components:
24494
25024
  path: { type: string }
24495
25025
  body: { type: string }
24496
25026
 
24497
- CodeChatCrossEdgesBodyDto:
25027
+ CodeChatCrossEdgesBodyDto:
25028
+ type: object
25029
+ properties:
25030
+ repoIds:
25031
+ type: array
25032
+ items: { type: string, format: uuid }
25033
+
25034
+ CodeChatCrossEdgesResultDto:
25035
+ type: object
25036
+ required: [items, completeness]
25037
+ properties:
25038
+ items:
25039
+ type: array
25040
+ items:
25041
+ type: object
25042
+ additionalProperties: true
25043
+ completeness: { type: string, enum: [partial, unknown] }
25044
+ gateNote: { type: string }
25045
+
25046
+ CodeChatContextPackBodyDto:
25047
+ type: object
25048
+ properties:
25049
+ question: { type: string }
25050
+ symbol: { type: string }
25051
+ maxTokensApprox: { type: integer }
25052
+ repoIds:
25053
+ type: array
25054
+ items: { type: string, format: uuid }
25055
+
25056
+ CodeChatContextPackDto:
25057
+ type: object
25058
+ required: [summary, symbols, references, citations, snippets]
25059
+ properties:
25060
+ repoId: { type: string, format: uuid }
25061
+ repoName: { type: string }
25062
+ commitSha: { type: string, nullable: true }
25063
+ summary: { type: string }
25064
+ symbols:
25065
+ type: array
25066
+ items:
25067
+ type: object
25068
+ additionalProperties: true
25069
+ references:
25070
+ type: array
25071
+ items:
25072
+ type: object
25073
+ additionalProperties: true
25074
+ blastRadiusPreview:
25075
+ type: object
25076
+ additionalProperties: true
25077
+ citations:
25078
+ type: array
25079
+ items:
25080
+ type: object
25081
+ additionalProperties: true
25082
+ snippets:
25083
+ type: array
25084
+ items: { type: string }
25085
+
25086
+ CodeInsightsMetricProvenance:
25087
+ type: string
25088
+ enum: [measured, derived, estimated, unavailable]
25089
+ description: >
25090
+ Where a metric value came from: `measured` (direct tool output),
25091
+ `derived` (computed from measured inputs, e.g. the maintainability band),
25092
+ `estimated` (heuristic proxy, e.g. test-to-source ratio), or `unavailable`
25093
+ (tool missing/failed, or the language is unsupported). Keyed per metric in
25094
+ `CodeInsightsMetricsDto.provenance`.
25095
+
25096
+ CodeInsightsMaintainabilityBand:
25097
+ type: string
25098
+ enum: [green, yellow, red]
25099
+ description: CC/LOC-derived maintainability band (documented heuristic, not Halstead MI).
25100
+
25101
+ CodeInsightsMetricsStatus:
25102
+ type: string
25103
+ enum: [ok, failed, skipped]
25104
+ description: >
25105
+ Outcome of the repo's latest metrics scan: `ok` (at least one tool measured),
25106
+ `failed` (every tool failed — metric fields are null with `unavailable`
25107
+ provenance), `skipped` (stage ran but found no measurable source).
25108
+
25109
+ CodeInsightsFindingSeverity:
25110
+ type: string
25111
+ enum: [critical, high, medium, low]
25112
+
25113
+ CodeInsightsFindingCategory:
25114
+ type: string
25115
+ enum:
25116
+ [
25117
+ duplication,
25118
+ complexity,
25119
+ proliferation,
25120
+ coverage,
25121
+ anemic_domain,
25122
+ context_leak,
25123
+ tx_boundary,
25124
+ error_handling,
25125
+ config_cohesion,
25126
+ resilience_patterns,
25127
+ circular_deps,
25128
+ fan_in_hotspot,
25129
+ ]
25130
+ description: >
25131
+ Deterministic categories (`duplication`, `complexity`, `proliferation`,
25132
+ `coverage`, `circular_deps`, `fan_in_hotspot`) plus LLM semantic detectors
25133
+ (`anemic_domain`, `context_leak`, `tx_boundary`, `error_handling`,
25134
+ `config_cohesion`, `resilience_patterns`). Coupling categories are written
25135
+ only by Design risks runs (`source=deterministic` on the design run id).
25136
+
25137
+ CodeInsightsFindingSource:
25138
+ type: string
25139
+ enum: [deterministic, llm]
25140
+ description: >
25141
+ `deterministic` = measured Code Insights rules; `llm` = AI-detected
25142
+ semantic findings (separate agent pass; never blended in scoring).
25143
+
25144
+ CodeInsightsMetricsDto:
25145
+ type: object
25146
+ required: [runId, measuredAt, metricsStatus, structureCounts, provenance, toolVersions]
25147
+ properties:
25148
+ runId:
25149
+ type: string
25150
+ description: Readiness run that produced this metrics row.
25151
+ defaultBranch:
25152
+ type: string
25153
+ nullable: true
25154
+ description: >
25155
+ Default branch at scan time from the linked readiness run, when
25156
+ `runId` matches a row in `tai_workspace_readiness_runs`.
25157
+ scannedCommitSha:
25158
+ type: string
25159
+ nullable: true
25160
+ description: >
25161
+ Git commit (default branch tip) analyzed by the readiness run, when
25162
+ known. Null for seed runs or when the run record is missing.
25163
+ measuredAt:
25164
+ type: string
25165
+ format: date-time
25166
+ metricsStatus:
25167
+ $ref: "#/components/schemas/CodeInsightsMetricsStatus"
25168
+ locTotal:
25169
+ type: integer
25170
+ nullable: true
25171
+ filesTotal:
25172
+ type: integer
25173
+ nullable: true
25174
+ ccAvg:
25175
+ type: number
25176
+ nullable: true
25177
+ description: Mean cyclomatic complexity across analyzed functions.
25178
+ ccMax:
25179
+ type: integer
25180
+ nullable: true
25181
+ ccP90:
25182
+ type: number
25183
+ nullable: true
25184
+ description: 90th percentile function cyclomatic complexity (nearest-rank).
25185
+ dupPct:
25186
+ type: number
25187
+ nullable: true
25188
+ description: Duplicated lines as a percentage of analyzed lines (0–100).
25189
+ maintainabilityBand:
25190
+ allOf:
25191
+ - $ref: "#/components/schemas/CodeInsightsMaintainabilityBand"
25192
+ nullable: true
25193
+ coveragePct:
25194
+ type: number
25195
+ nullable: true
25196
+ description: Reserved for per-repo SonarQube enrichment (v2); null in v1.
25197
+ debtRatio:
25198
+ type: number
25199
+ nullable: true
25200
+ description: Reserved for per-repo SonarQube enrichment (v2); null in v1.
25201
+ structureCounts:
25202
+ type: object
25203
+ additionalProperties: true
25204
+ description: >
25205
+ Heuristic structure counters: dto/mapper/config/exception file + LOC
25206
+ counts, test/source LOC split, per-language LOC, functions_analyzed,
25207
+ test_ratio, dto_mapper_share_pct.
25208
+ provenance:
25209
+ type: object
25210
+ additionalProperties:
25211
+ $ref: "#/components/schemas/CodeInsightsMetricProvenance"
25212
+ description: Per-metric provenance keyed by DTO field name (e.g. `ccAvg`, `dupPct`, `testRatio`).
25213
+ toolVersions:
25214
+ type: object
25215
+ additionalProperties: { type: string }
25216
+ description: Tool name → version string for the tools that produced this row.
25217
+
25218
+ CodeInsightsHotspotDto:
25219
+ type: object
25220
+ required: [filePath, flags]
25221
+ properties:
25222
+ filePath:
25223
+ type: string
25224
+ description: Repo-relative file path.
25225
+ loc:
25226
+ type: integer
25227
+ nullable: true
25228
+ ccMax:
25229
+ type: integer
25230
+ nullable: true
25231
+ description: Max function cyclomatic complexity in the file.
25232
+ paramsMax:
25233
+ type: integer
25234
+ nullable: true
25235
+ nestingMax:
25236
+ type: integer
25237
+ nullable: true
25238
+ description: Max nested control structures (null when the analyzer does not report nesting).
25239
+ dupPct:
25240
+ type: number
25241
+ nullable: true
25242
+ description: Estimated per-file duplicated line share (0–100).
25243
+ flags:
25244
+ type: array
25245
+ items: { type: string }
25246
+ description: Subset of `god_file`, `high_cc`, `long_params`, `deep_nesting`.
25247
+ peakFunction:
25248
+ type: string
25249
+ nullable: true
25250
+ description: Name of the function that owns `ccMax` (lizard). Null on snapshots taken before peak-function capture.
25251
+ peakStartLine:
25252
+ type: integer
25253
+ nullable: true
25254
+ description: 1-based start line of `peakFunction`.
25255
+ peakEndLine:
25256
+ type: integer
25257
+ nullable: true
25258
+ description: 1-based end line of `peakFunction`.
25259
+ peakParams:
25260
+ type: integer
25261
+ nullable: true
25262
+ description: Parameter count of `peakFunction` (not file-wide `paramsMax`). Null on older snapshots.
25263
+
25264
+ CodeInsightsFindingDto:
25265
+ type: object
25266
+ required: [id, severity, category, title, explanation, evidence, source, runId, createdAt]
25267
+ properties:
25268
+ id:
25269
+ type: string
25270
+ format: uuid
25271
+ severity:
25272
+ $ref: "#/components/schemas/CodeInsightsFindingSeverity"
25273
+ category:
25274
+ $ref: "#/components/schemas/CodeInsightsFindingCategory"
25275
+ title:
25276
+ type: string
25277
+ explanation:
25278
+ type: string
25279
+ evidence:
25280
+ type: object
25281
+ additionalProperties: true
25282
+ description: Measured values and thresholds backing the finding.
25283
+ remediation:
25284
+ type: string
25285
+ nullable: true
25286
+ source:
25287
+ $ref: "#/components/schemas/CodeInsightsFindingSource"
25288
+ runId:
25289
+ type: string
25290
+ createdAt:
25291
+ type: string
25292
+ format: date-time
25293
+
25294
+ CodeInsightsFindingsBySeverityDto:
25295
+ type: object
25296
+ required: [critical, high, medium, low]
25297
+ properties:
25298
+ critical: { type: integer, minimum: 0 }
25299
+ high: { type: integer, minimum: 0 }
25300
+ medium: { type: integer, minimum: 0 }
25301
+ low: { type: integer, minimum: 0 }
25302
+
25303
+ CodeInsightsRepoListItemDto:
25304
+ type: object
25305
+ required:
25306
+ [repoId, repoName, language, providerSlug, webUrl, badges, findingsBySeverity, provenance]
25307
+ properties:
25308
+ repoId:
25309
+ type: string
25310
+ format: uuid
25311
+ repoName:
25312
+ type: string
25313
+ language:
25314
+ type: string
25315
+ providerSlug:
25316
+ type: string
25317
+ description: "owner/repo on the VCS provider."
25318
+ webUrl:
25319
+ type: string
25320
+ lastMeasuredAt:
25321
+ type: string
25322
+ format: date-time
25323
+ nullable: true
25324
+ description: Null when the repo is pending its first metrics scan.
25325
+ metricsStatus:
25326
+ allOf:
25327
+ - $ref: "#/components/schemas/CodeInsightsMetricsStatus"
25328
+ nullable: true
25329
+ locTotal:
25330
+ type: integer
25331
+ nullable: true
25332
+ ccAvg:
25333
+ type: number
25334
+ nullable: true
25335
+ ccMax:
25336
+ type: integer
25337
+ nullable: true
25338
+ dupPct:
25339
+ type: number
25340
+ nullable: true
25341
+ maintainabilityBand:
25342
+ allOf:
25343
+ - $ref: "#/components/schemas/CodeInsightsMaintainabilityBand"
25344
+ nullable: true
25345
+ badges:
25346
+ type: array
25347
+ items: { type: string }
25348
+ description: >
25349
+ Active threshold badges from the latest scan: subset of `god_files`,
25350
+ `high_complexity`, `duplication`, `proliferation`, `low_test_ratio`.
25351
+ findingsBySeverity:
25352
+ $ref: "#/components/schemas/CodeInsightsFindingsBySeverityDto"
25353
+ provenance:
25354
+ type: object
25355
+ additionalProperties:
25356
+ $ref: "#/components/schemas/CodeInsightsMetricProvenance"
25357
+
25358
+ CodeInsightsRepoListDto:
25359
+ allOf:
25360
+ - $ref: "#/components/schemas/PageMetaDto"
25361
+ - type: object
25362
+ required: [items]
25363
+ properties:
25364
+ items:
25365
+ type: array
25366
+ items:
25367
+ $ref: "#/components/schemas/CodeInsightsRepoListItemDto"
25368
+
25369
+ CodeInsightsRepoDetailDto:
25370
+ type: object
25371
+ required:
25372
+ [
25373
+ repoId,
25374
+ repoName,
25375
+ language,
25376
+ providerSlug,
25377
+ webUrl,
25378
+ metrics,
25379
+ hotspots,
25380
+ findings,
25381
+ designAnalysis,
25382
+ ]
25383
+ properties:
25384
+ repoId:
25385
+ type: string
25386
+ format: uuid
25387
+ repoName:
25388
+ type: string
25389
+ language:
25390
+ type: string
25391
+ providerSlug:
25392
+ type: string
25393
+ webUrl:
25394
+ type: string
25395
+ metrics:
25396
+ allOf:
25397
+ - $ref: "#/components/schemas/CodeInsightsMetricsDto"
25398
+ nullable: true
25399
+ description: Null when the repo is pending its first metrics scan.
25400
+ hotspots:
25401
+ type: array
25402
+ items:
25403
+ $ref: "#/components/schemas/CodeInsightsHotspotDto"
25404
+ findings:
25405
+ type: array
25406
+ items:
25407
+ $ref: "#/components/schemas/CodeInsightsFindingDto"
25408
+ description: >
25409
+ Deterministic findings from the latest metrics scan plus LLM findings from the
25410
+ latest **succeeded** Design risks run only. Stale LLM rows from older design runs
25411
+ are not returned.
25412
+ designAnalysis:
25413
+ allOf:
25414
+ - $ref: "#/components/schemas/CodeInsightsDesignAnalysisDto"
25415
+ nullable: true
25416
+ description: >
25417
+ Latest Design risks run of any status (for UI polling). Null when Design risks
25418
+ has never been enqueued for this repo.
25419
+
25420
+ CodeInsightsDesignAnalysisDto:
25421
+ type: object
25422
+ required: [runId, status, finishedAt, errorCode, errorDetail]
25423
+ properties:
25424
+ runId:
25425
+ type: string
25426
+ format: uuid
25427
+ status:
25428
+ type: string
25429
+ enum: [queued, running, succeeded, failed, partial_failed]
25430
+ finishedAt:
25431
+ type: string
25432
+ format: date-time
25433
+ nullable: true
25434
+ errorCode:
25435
+ type: string
25436
+ nullable: true
25437
+ errorDetail:
25438
+ type: string
25439
+ nullable: true
25440
+
25441
+ CodeInsightsDesignAnalyzeResponseDto:
25442
+ type: object
25443
+ required: [runId]
25444
+ properties:
25445
+ runId:
25446
+ type: string
25447
+ format: uuid
25448
+ description: Enqueued Design risks run id (`tai_workspace_readiness_runs.id`).
25449
+
25450
+ CodeInsightsOrgHotspotDto:
25451
+ allOf:
25452
+ - $ref: "#/components/schemas/CodeInsightsHotspotDto"
25453
+ - type: object
25454
+ required: [repoId, repoName]
25455
+ properties:
25456
+ repoId:
25457
+ type: string
25458
+ format: uuid
25459
+ repoName:
25460
+ type: string
25461
+
25462
+ CodeInsightsSonarDto:
24498
25463
  type: object
25464
+ required: [connected]
24499
25465
  properties:
24500
- repoIds:
24501
- type: array
24502
- items: { type: string, format: uuid }
25466
+ connected:
25467
+ type: boolean
25468
+ description: Whether a SonarQube source is configured for the workspace.
25469
+ coveragePct:
25470
+ type: number
25471
+ nullable: true
25472
+ description: Org-level SonarQube coverage from the latest precomputed quality snapshot.
25473
+ techDebtRatioPct:
25474
+ type: number
25475
+ nullable: true
25476
+ description: Org-level SonarQube SQALE technical debt ratio from the latest quality snapshot.
24503
25477
 
24504
- CodeChatCrossEdgesResultDto:
25478
+ CodeInsightsSummaryDto:
24505
25479
  type: object
24506
- required: [items, completeness]
25480
+ required: [reposMeasured, reposPending, findingsBySeverity, topHotspots, sonar]
24507
25481
  properties:
24508
- items:
25482
+ reposMeasured:
25483
+ type: integer
25484
+ minimum: 0
25485
+ description: Active repos whose latest metrics scan completed (`ok`).
25486
+ reposPending:
25487
+ type: integer
25488
+ minimum: 0
25489
+ description: Active repos without a completed metrics scan (never scanned, or only failed/skipped).
25490
+ ccAvgMedian:
25491
+ type: number
25492
+ nullable: true
25493
+ description: Unweighted median of latest `ccAvg` across measured repos (null when none measured).
25494
+ dupPctMedian:
25495
+ type: number
25496
+ nullable: true
25497
+ description: Unweighted median of latest `dupPct` across measured repos (null when none measured).
25498
+ findingsBySeverity:
25499
+ $ref: "#/components/schemas/CodeInsightsFindingsBySeverityDto"
25500
+ topHotspots:
24509
25501
  type: array
24510
25502
  items:
24511
- type: object
24512
- additionalProperties: true
24513
- completeness: { type: string, enum: [partial, unknown] }
24514
- gateNote: { type: string }
25503
+ $ref: "#/components/schemas/CodeInsightsOrgHotspotDto"
25504
+ description: Org top-10 complexity hotspots by `ccMax` (current per-repo snapshots).
25505
+ sonar:
25506
+ $ref: "#/components/schemas/CodeInsightsSonarDto"
24515
25507
 
24516
- CodeChatContextPackBodyDto:
25508
+ InsightsTestPyramidMaturityDto:
25509
+ type: string
25510
+ enum: [missing, emerging, established, mature]
25511
+ description: >
25512
+ Presence maturity (model A) using count-based layer presence
25513
+ (`fileCount > 0`), not AF signal-inclusive `present`.
25514
+
25515
+ InsightsTestPyramidShapeLabelDto:
25516
+ type: string
25517
+ enum: [insufficient_data, base_heavy, balanced, top_heavy, middle_heavy]
25518
+ description: >
25519
+ Advisory shape label vs fixed 70/20/10. `insufficient_data` when total
25520
+ classified test files < 10 (band percents are null).
25521
+
25522
+ InsightsTestPyramidShapeDto:
24517
25523
  type: object
25524
+ required: [label, totalClassifiedFiles, basePercent, middlePercent, topPercent, targets]
24518
25525
  properties:
24519
- question: { type: string }
24520
- symbol: { type: string }
24521
- maxTokensApprox: { type: integer }
24522
- repoIds:
25526
+ label:
25527
+ $ref: "#/components/schemas/InsightsTestPyramidShapeLabelDto"
25528
+ totalClassifiedFiles:
25529
+ type: integer
25530
+ minimum: 0
25531
+ description: Sum of classified test **files** across the five layers (not test cases).
25532
+ basePercent:
25533
+ type: number
25534
+ nullable: true
25535
+ description: Share of classified files in unit (base). Null when insufficient_data.
25536
+ middlePercent:
25537
+ type: number
25538
+ nullable: true
25539
+ description: >
25540
+ Share in integration + contract + acceptance_bdd (middle). Null when
25541
+ insufficient_data.
25542
+ topPercent:
25543
+ type: number
25544
+ nullable: true
25545
+ description: Share in e2e (top). Null when insufficient_data.
25546
+ targets:
25547
+ type: object
25548
+ required: [basePercent, middlePercent, topPercent]
25549
+ properties:
25550
+ basePercent: { type: number, enum: [70] }
25551
+ middlePercent: { type: number, enum: [20] }
25552
+ topPercent: { type: number, enum: [10] }
25553
+
25554
+ InsightsTestPyramidLayerCountsDto:
25555
+ type: object
25556
+ required: [unit, integration, acceptance_bdd, contract, e2e]
25557
+ properties:
25558
+ unit: { type: integer, minimum: 0 }
25559
+ integration: { type: integer, minimum: 0 }
25560
+ acceptance_bdd: { type: integer, minimum: 0 }
25561
+ contract: { type: integer, minimum: 0 }
25562
+ e2e: { type: integer, minimum: 0 }
25563
+
25564
+ InsightsTestPyramidLayerPresentDto:
25565
+ type: object
25566
+ required: [unit, integration, acceptance_bdd, contract, e2e]
25567
+ properties:
25568
+ unit: { type: boolean }
25569
+ integration: { type: boolean }
25570
+ acceptance_bdd: { type: boolean }
25571
+ contract: { type: boolean }
25572
+ e2e: { type: boolean }
25573
+
25574
+ InsightsTestPyramidLayerPresenceDto:
25575
+ type: object
25576
+ required: [presentRepos, applicableRepos, percent, missingRepoIds, missingRepoNames]
25577
+ properties:
25578
+ presentRepos: { type: integer, minimum: 0 }
25579
+ applicableRepos: { type: integer, minimum: 0 }
25580
+ percent:
25581
+ type: integer
25582
+ nullable: true
25583
+ minimum: 0
25584
+ maximum: 100
25585
+ missingRepoIds:
24523
25586
  type: array
24524
25587
  items: { type: string, format: uuid }
25588
+ missingRepoNames:
25589
+ type: array
25590
+ items: { type: string }
24525
25591
 
24526
- CodeChatContextPackDto:
25592
+ InsightsTestPyramidGapRepoDto:
24527
25593
  type: object
24528
- required: [summary, symbols, references, citations, snippets]
25594
+ required: [repoId, repoName]
24529
25595
  properties:
24530
25596
  repoId: { type: string, format: uuid }
24531
25597
  repoName: { type: string }
24532
- commitSha: { type: string, nullable: true }
24533
- summary: { type: string }
24534
- symbols:
25598
+
25599
+ InsightsTestPyramidGapsByLayerDto:
25600
+ type: object
25601
+ required: [unit, integration, acceptance_bdd, contract, e2e]
25602
+ properties:
25603
+ unit:
24535
25604
  type: array
24536
- items:
24537
- type: object
24538
- additionalProperties: true
24539
- references:
25605
+ items: { $ref: "#/components/schemas/InsightsTestPyramidGapRepoDto" }
25606
+ integration:
24540
25607
  type: array
24541
- items:
24542
- type: object
24543
- additionalProperties: true
24544
- blastRadiusPreview:
24545
- type: object
24546
- additionalProperties: true
24547
- citations:
25608
+ items: { $ref: "#/components/schemas/InsightsTestPyramidGapRepoDto" }
25609
+ acceptance_bdd:
24548
25610
  type: array
24549
- items:
24550
- type: object
24551
- additionalProperties: true
24552
- snippets:
25611
+ items: { $ref: "#/components/schemas/InsightsTestPyramidGapRepoDto" }
25612
+ contract:
24553
25613
  type: array
24554
- items: { type: string }
24555
-
24556
- CodeInsightsMetricProvenance:
24557
- type: string
24558
- enum: [measured, derived, estimated, unavailable]
24559
- description: >
24560
- Where a metric value came from: `measured` (direct tool output),
24561
- `derived` (computed from measured inputs, e.g. the maintainability band),
24562
- `estimated` (heuristic proxy, e.g. test-to-source ratio), or `unavailable`
24563
- (tool missing/failed, or the language is unsupported). Keyed per metric in
24564
- `CodeInsightsMetricsDto.provenance`.
24565
-
24566
- CodeInsightsMaintainabilityBand:
24567
- type: string
24568
- enum: [green, yellow, red]
24569
- description: CC/LOC-derived maintainability band (documented heuristic, not Halstead MI).
24570
-
24571
- CodeInsightsMetricsStatus:
24572
- type: string
24573
- enum: [ok, failed, skipped]
24574
- description: >
24575
- Outcome of the repo's latest metrics scan: `ok` (at least one tool measured),
24576
- `failed` (every tool failed — metric fields are null with `unavailable`
24577
- provenance), `skipped` (stage ran but found no measurable source).
25614
+ items: { $ref: "#/components/schemas/InsightsTestPyramidGapRepoDto" }
25615
+ e2e:
25616
+ type: array
25617
+ items: { $ref: "#/components/schemas/InsightsTestPyramidGapRepoDto" }
24578
25618
 
24579
- CodeInsightsFindingSeverity:
24580
- type: string
24581
- enum: [critical, high, medium, low]
25619
+ InsightsTestPyramidMaturityCountsDto:
25620
+ type: object
25621
+ required: [missing, emerging, established, mature]
25622
+ properties:
25623
+ missing: { type: integer, minimum: 0 }
25624
+ emerging: { type: integer, minimum: 0 }
25625
+ established: { type: integer, minimum: 0 }
25626
+ mature: { type: integer, minimum: 0 }
24582
25627
 
24583
- CodeInsightsFindingCategory:
24584
- type: string
24585
- enum:
24586
- [
24587
- duplication,
24588
- complexity,
24589
- proliferation,
24590
- coverage,
24591
- anemic_domain,
24592
- context_leak,
24593
- tx_boundary,
24594
- error_handling,
24595
- config_cohesion,
24596
- resilience_patterns,
24597
- circular_deps,
24598
- fan_in_hotspot,
24599
- ]
24600
- description: >
24601
- Deterministic categories (`duplication`, `complexity`, `proliferation`,
24602
- `coverage`, `circular_deps`, `fan_in_hotspot`) plus LLM semantic detectors
24603
- (`anemic_domain`, `context_leak`, `tx_boundary`, `error_handling`,
24604
- `config_cohesion`, `resilience_patterns`). Coupling categories are written
24605
- only by Design risks runs (`source=deterministic` on the design run id).
25628
+ InsightsTestPyramidLayerPresenceMapDto:
25629
+ type: object
25630
+ required: [unit, integration, acceptance_bdd, contract, e2e]
25631
+ properties:
25632
+ unit: { $ref: "#/components/schemas/InsightsTestPyramidLayerPresenceDto" }
25633
+ integration: { $ref: "#/components/schemas/InsightsTestPyramidLayerPresenceDto" }
25634
+ acceptance_bdd: { $ref: "#/components/schemas/InsightsTestPyramidLayerPresenceDto" }
25635
+ contract: { $ref: "#/components/schemas/InsightsTestPyramidLayerPresenceDto" }
25636
+ e2e: { $ref: "#/components/schemas/InsightsTestPyramidLayerPresenceDto" }
24606
25637
 
24607
- CodeInsightsFindingSource:
25638
+ InsightsTestPyramidMaturityDeltaDto:
24608
25639
  type: string
24609
- enum: [deterministic, llm]
25640
+ enum: [up, down, unchanged, none]
24610
25641
  description: >
24611
- `deterministic` = measured Code Insights rules; `llm` = AI-detected
24612
- semantic findings (separate agent pass; never blended in scoring).
25642
+ Insights maturity rank change vs the immediately previous pyramid point
25643
+ (missing 0, emerging 1, established 2, mature 3). `none` when the repo
25644
+ has no previous succeeded/partial_failed/failed point.
24613
25645
 
24614
- CodeInsightsMetricsDto:
25646
+ InsightsTestPyramidConfidenceDto:
25647
+ type: string
25648
+ enum: [high, medium, low]
25649
+
25650
+ InsightsTestPyramidLayerConfidenceDto:
24615
25651
  type: object
24616
- required: [runId, measuredAt, metricsStatus, structureCounts, provenance, toolVersions]
25652
+ required: [unit, integration, acceptance_bdd, contract, e2e]
24617
25653
  properties:
24618
- runId:
24619
- type: string
24620
- description: Readiness run that produced this metrics row.
24621
- defaultBranch:
24622
- type: string
25654
+ unit: { $ref: "#/components/schemas/InsightsTestPyramidConfidenceDto" }
25655
+ integration: { $ref: "#/components/schemas/InsightsTestPyramidConfidenceDto" }
25656
+ acceptance_bdd: { $ref: "#/components/schemas/InsightsTestPyramidConfidenceDto" }
25657
+ contract: { $ref: "#/components/schemas/InsightsTestPyramidConfidenceDto" }
25658
+ e2e: { $ref: "#/components/schemas/InsightsTestPyramidConfidenceDto" }
25659
+
25660
+ InsightsTestPyramidCoverageRollupDto:
25661
+ type: object
25662
+ required: [reposWithCoverage, medianLinePercent]
25663
+ properties:
25664
+ reposWithCoverage:
25665
+ type: integer
25666
+ minimum: 0
25667
+ description: Repos whose overlaid `lineCoverage` is non-null.
25668
+ medianLinePercent:
25669
+ type: number
24623
25670
  nullable: true
25671
+ minimum: 0
25672
+ maximum: 100
24624
25673
  description: >
24625
- Default branch at scan time from the linked readiness run, when
24626
- `runId` matches a row in `tai_workspace_readiness_runs`.
24627
- scannedCommitSha:
24628
- type: string
24629
- nullable: true
25674
+ Median of repo `linePercent` among repos that have coverage. Null when
25675
+ `reposWithCoverage` is 0.
25676
+
25677
+ InsightsTestPyramidCiQualityDto:
25678
+ type: object
25679
+ nullable: true
25680
+ required: [ciFailureRatePercent, bucketEnd]
25681
+ properties:
25682
+ ciFailureRatePercent:
25683
+ type: number
25684
+ minimum: 0
25685
+ maximum: 100
24630
25686
  description: >
24631
- Git commit (default branch tip) analyzed by the readiness run, when
24632
- known. Null for seed runs or when the run record is missing.
24633
- measuredAt:
25687
+ Latest org dashboard `quality.ciFailureRatePercent`, falling back to
25688
+ `quality.ciBuildFailRatePercent`.
25689
+ ciFlakinessPercent:
25690
+ type: number
25691
+ minimum: 0
25692
+ maximum: 100
25693
+ description: Included only when `quality.ciFlakinessPercent` is a finite number.
25694
+ bucketEnd:
24634
25695
  type: string
24635
- format: date-time
24636
- metricsStatus:
24637
- $ref: "#/components/schemas/CodeInsightsMetricsStatus"
24638
- locTotal:
25696
+ description: Dashboard metrics bucket end for the org snapshot.
25697
+
25698
+ InsightsTestPyramidSummaryDto:
25699
+ type: object
25700
+ required:
25701
+ - workspaceId
25702
+ - generatedAt
25703
+ - reposWithPyramid
25704
+ - reposFromDegradedRuns
25705
+ - totalClassifiedFiles
25706
+ - shape
25707
+ - layerPresence
25708
+ - maturityCounts
25709
+ - gapsByLayer
25710
+ - newestScannedAt
25711
+ - maturedRepoCount
25712
+ - slippedRepoCount
25713
+ - previousShape
25714
+ - coverage
25715
+ - e2eCrossRepoCandidateCount
25716
+ - reposWithHotspots
25717
+ - ciQuality
25718
+ properties:
25719
+ workspaceId: { type: string, format: uuid }
25720
+ generatedAt: { type: string, format: date-time }
25721
+ reposWithPyramid: { type: integer, minimum: 0 }
25722
+ reposFromDegradedRuns:
25723
+ type: array
25724
+ items: { type: string, format: uuid }
25725
+ description: Repos whose newest pyramid came from a non-succeeded readiness run.
25726
+ totalClassifiedFiles:
24639
25727
  type: integer
25728
+ minimum: 0
25729
+ description: Workspace sum of classified test files (not cases).
25730
+ shape:
25731
+ $ref: "#/components/schemas/InsightsTestPyramidShapeDto"
25732
+ layerPresence:
25733
+ $ref: "#/components/schemas/InsightsTestPyramidLayerPresenceMapDto"
25734
+ maturityCounts:
25735
+ $ref: "#/components/schemas/InsightsTestPyramidMaturityCountsDto"
25736
+ gapsByLayer:
25737
+ $ref: "#/components/schemas/InsightsTestPyramidGapsByLayerDto"
25738
+ newestScannedAt:
25739
+ type: string
25740
+ format: date-time
24640
25741
  nullable: true
24641
- filesTotal:
25742
+ description: Latest per-repo `scannedAt`. Null when `reposWithPyramid` is 0.
25743
+ maturedRepoCount:
24642
25744
  type: integer
24643
- nullable: true
24644
- ccAvg:
24645
- type: number
24646
- nullable: true
24647
- description: Mean cyclomatic complexity across analyzed functions.
24648
- ccMax:
25745
+ minimum: 0
25746
+ description: Repos whose Insights maturity rank increased vs the previous point.
25747
+ slippedRepoCount:
24649
25748
  type: integer
24650
- nullable: true
24651
- ccP90:
24652
- type: number
24653
- nullable: true
24654
- description: 90th percentile function cyclomatic complexity (nearest-rank).
24655
- dupPct:
24656
- type: number
24657
- nullable: true
24658
- description: Duplicated lines as a percentage of analyzed lines (0–100).
24659
- maintainabilityBand:
25749
+ minimum: 0
25750
+ description: Repos whose Insights maturity rank decreased vs the previous point.
25751
+ previousShape:
24660
25752
  allOf:
24661
- - $ref: "#/components/schemas/CodeInsightsMaintainabilityBand"
24662
- nullable: true
24663
- coveragePct:
24664
- type: number
24665
- nullable: true
24666
- description: Reserved for per-repo SonarQube enrichment (v2); null in v1.
24667
- debtRatio:
24668
- type: number
25753
+ - $ref: "#/components/schemas/InsightsTestPyramidShapeDto"
24669
25754
  nullable: true
24670
- description: Reserved for per-repo SonarQube enrichment (v2); null in v1.
24671
- structureCounts:
24672
- type: object
24673
- additionalProperties: true
24674
25755
  description: >
24675
- Heuristic structure counters: dto/mapper/config/exception file + LOC
24676
- counts, test/source LOC split, per-language LOC, functions_analyzed,
24677
- test_ratio, dto_mapper_share_pct.
24678
- provenance:
24679
- type: object
24680
- additionalProperties:
24681
- $ref: "#/components/schemas/CodeInsightsMetricProvenance"
24682
- description: Per-metric provenance keyed by DTO field name (e.g. `ccAvg`, `dupPct`, `testRatio`).
24683
- toolVersions:
24684
- type: object
24685
- additionalProperties: { type: string }
24686
- description: Tool name → version string for the tools that produced this row.
25756
+ Insights workspace shape from previous-point file totals for repos that
25757
+ have a previous point. Null when no repo has a previous point.
25758
+ coverage:
25759
+ $ref: "#/components/schemas/InsightsTestPyramidCoverageRollupDto"
25760
+ e2eCrossRepoCandidateCount:
25761
+ type: integer
25762
+ minimum: 0
25763
+ reposWithHotspots:
25764
+ type: integer
25765
+ minimum: 0
25766
+ description: Repos whose latest Code Insights snapshot has `hotspotCount` > 0.
25767
+ ciQuality:
25768
+ $ref: "#/components/schemas/InsightsTestPyramidCiQualityDto"
24687
25769
 
24688
- CodeInsightsHotspotDto:
25770
+ InsightsTestPyramidRepoItemDto:
24689
25771
  type: object
24690
- required: [filePath, flags]
25772
+ required:
25773
+ - repoId
25774
+ - repoName
25775
+ - scannedAt
25776
+ - currentRunStatus
25777
+ - maturity
25778
+ - layerFileCounts
25779
+ - layerPresent
25780
+ - totalClassifiedFiles
25781
+ - shape
25782
+ - previousMaturity
25783
+ - maturityDelta
25784
+ - previousShapeLabel
25785
+ - lineCoverage
25786
+ - lowestConfidence
25787
+ - layerConfidence
25788
+ - evidenceCount
25789
+ - frameworks
25790
+ - layerApplicable
25791
+ - e2eCrossRepoCandidate
25792
+ - hotspotCount
24691
25793
  properties:
24692
- filePath:
24693
- type: string
24694
- description: Repo-relative file path.
24695
- loc:
24696
- type: integer
24697
- nullable: true
24698
- ccMax:
24699
- type: integer
25794
+ repoId: { type: string, format: uuid }
25795
+ repoName: { type: string }
25796
+ scannedAt: { type: string, format: date-time }
25797
+ currentRunStatus:
25798
+ $ref: "#/components/schemas/TestPyramidRunStatusDto"
25799
+ maturity:
25800
+ $ref: "#/components/schemas/InsightsTestPyramidMaturityDto"
25801
+ previousMaturity:
25802
+ allOf:
25803
+ - $ref: "#/components/schemas/InsightsTestPyramidMaturityDto"
24700
25804
  nullable: true
24701
- description: Max function cyclomatic complexity in the file.
24702
- paramsMax:
24703
- type: integer
25805
+ maturityDelta:
25806
+ $ref: "#/components/schemas/InsightsTestPyramidMaturityDeltaDto"
25807
+ previousShapeLabel:
25808
+ allOf:
25809
+ - $ref: "#/components/schemas/InsightsTestPyramidShapeLabelDto"
24704
25810
  nullable: true
24705
- nestingMax:
25811
+ layerFileCounts:
25812
+ $ref: "#/components/schemas/InsightsTestPyramidLayerCountsDto"
25813
+ layerPresent:
25814
+ $ref: "#/components/schemas/InsightsTestPyramidLayerPresentDto"
25815
+ layerApplicable:
25816
+ allOf:
25817
+ - $ref: "#/components/schemas/InsightsTestPyramidLayerPresentDto"
25818
+ description: Snapshot `layers.*.applicable` for each layer.
25819
+ totalClassifiedFiles: { type: integer, minimum: 0 }
25820
+ shape:
25821
+ $ref: "#/components/schemas/InsightsTestPyramidShapeDto"
25822
+ lineCoverage:
25823
+ allOf:
25824
+ - $ref: "#/components/schemas/TestPyramidLineCoverageDto"
25825
+ description: >
25826
+ Same overlay as AF progress — latest Sonar row first, else snapshot
25827
+ `testPyramid.lineCoverage`. Null when both are missing. Not Code Insights
25828
+ `coveragePct`.
25829
+ lowestConfidence:
25830
+ allOf:
25831
+ - $ref: "#/components/schemas/InsightsTestPyramidConfidenceDto"
25832
+ description: >
25833
+ Minimum confidence among layers with Insights presence (`fileCount > 0`);
25834
+ if none present, minimum of applicable layers. Order low < medium < high.
25835
+ layerConfidence:
25836
+ $ref: "#/components/schemas/InsightsTestPyramidLayerConfidenceDto"
25837
+ evidenceCount:
24706
25838
  type: integer
24707
- nullable: true
24708
- description: Max nested control structures (null when the analyzer does not report nesting).
24709
- dupPct:
24710
- type: number
24711
- nullable: true
24712
- description: Estimated per-file duplicated line share (0–100).
24713
- flags:
25839
+ minimum: 0
25840
+ description: Sum of layer `evidence[]` lengths on the latest snapshot.
25841
+ frameworks:
24714
25842
  type: array
25843
+ maxItems: 8
24715
25844
  items: { type: string }
24716
- description: Subset of `god_file`, `high_cc`, `long_params`, `deep_nesting`.
24717
- peakFunction:
24718
- type: string
24719
- nullable: true
24720
- description: Name of the function that owns `ccMax` (lizard). Null on snapshots taken before peak-function capture.
24721
- peakStartLine:
24722
- type: integer
24723
- nullable: true
24724
- description: 1-based start line of `peakFunction`.
24725
- peakEndLine:
24726
- type: integer
24727
- nullable: true
24728
- description: 1-based end line of `peakFunction`.
24729
- peakParams:
25845
+ description: Unique framework names across layers, capped at 8.
25846
+ e2eCrossRepoCandidate: { type: boolean }
25847
+ hotspotCount:
24730
25848
  type: integer
24731
25849
  nullable: true
24732
- description: Parameter count of `peakFunction` (not file-wide `paramsMax`). Null on older snapshots.
25850
+ minimum: 0
25851
+ description: >
25852
+ Row count in `tai_workspace_repo_code_hotspots` for the repo's latest
25853
+ Code Insights metrics snapshot. Null when the repo has no metrics snapshot.
24733
25854
 
24734
- CodeInsightsFindingDto:
25855
+ InsightsTestPyramidRepoListDto:
24735
25856
  type: object
24736
- required: [id, severity, category, title, explanation, evidence, source, runId, createdAt]
25857
+ required: [items, total, limit, offset]
24737
25858
  properties:
24738
- id:
24739
- type: string
24740
- format: uuid
24741
- severity:
24742
- $ref: "#/components/schemas/CodeInsightsFindingSeverity"
24743
- category:
24744
- $ref: "#/components/schemas/CodeInsightsFindingCategory"
24745
- title:
24746
- type: string
24747
- explanation:
24748
- type: string
24749
- evidence:
24750
- type: object
24751
- additionalProperties: true
24752
- description: Measured values and thresholds backing the finding.
24753
- remediation:
24754
- type: string
24755
- nullable: true
24756
- source:
24757
- $ref: "#/components/schemas/CodeInsightsFindingSource"
24758
- runId:
24759
- type: string
24760
- createdAt:
24761
- type: string
24762
- format: date-time
25859
+ items:
25860
+ type: array
25861
+ items:
25862
+ $ref: "#/components/schemas/InsightsTestPyramidRepoItemDto"
25863
+ total: { type: integer, minimum: 0 }
25864
+ limit: { type: integer, minimum: 1 }
25865
+ offset: { type: integer, minimum: 0 }
25866
+ EvalExpectedSignalKindDto:
25867
+ type: string
25868
+ description: >
25869
+ Deterministic scorer kinds for golden-case expected signals. Case pass =
25870
+ all signals pass. No LLM-as-judge in v1.
25871
+ enum: [contains, not_contains, regex, json_path_equals]
24763
25872
 
24764
- CodeInsightsFindingsBySeverityDto:
24765
- type: object
24766
- required: [critical, high, medium, low]
24767
- properties:
24768
- critical: { type: integer, minimum: 0 }
24769
- high: { type: integer, minimum: 0 }
24770
- medium: { type: integer, minimum: 0 }
24771
- low: { type: integer, minimum: 0 }
25873
+ EvalAiProviderDto:
25874
+ type: string
25875
+ description: >
25876
+ Model provider vocabulary aligned with AI Usage `modelName` surfaces
25877
+ (`cursor` | `claude`).
25878
+ enum: [cursor, claude]
24772
25879
 
24773
- CodeInsightsRepoListItemDto:
25880
+ EvalExpectedSignalDto:
24774
25881
  type: object
24775
- required:
24776
- [repoId, repoName, language, providerSlug, webUrl, badges, findingsBySeverity, provenance]
25882
+ additionalProperties: false
25883
+ required: [id, kind]
25884
+ description: >
25885
+ One expected signal on a golden case. Use `value` for `contains` /
25886
+ `not_contains` (substring) and for `json_path_equals` (expected value as
25887
+ string). Use `pattern` for `regex`. Use `path` (JSONPath) for
25888
+ `json_path_equals`.
24777
25889
  properties:
24778
- repoId:
24779
- type: string
24780
- format: uuid
24781
- repoName:
24782
- type: string
24783
- language:
25890
+ id:
24784
25891
  type: string
24785
- providerSlug:
25892
+ minLength: 1
25893
+ maxLength: 64
25894
+ kind:
25895
+ $ref: "#/components/schemas/EvalExpectedSignalKindDto"
25896
+ value:
24786
25897
  type: string
24787
- description: "owner/repo on the VCS provider."
24788
- webUrl:
25898
+ maxLength: 8000
25899
+ description: >
25900
+ Substring for `contains` / `not_contains`, or expected value for
25901
+ `json_path_equals`.
25902
+ pattern:
24789
25903
  type: string
24790
- lastMeasuredAt:
25904
+ maxLength: 2000
25905
+ description: Regular expression source for `regex`.
25906
+ path:
24791
25907
  type: string
24792
- format: date-time
24793
- nullable: true
24794
- description: Null when the repo is pending its first metrics scan.
24795
- metricsStatus:
24796
- allOf:
24797
- - $ref: "#/components/schemas/CodeInsightsMetricsStatus"
24798
- nullable: true
24799
- locTotal:
24800
- type: integer
24801
- nullable: true
24802
- ccAvg:
24803
- type: number
24804
- nullable: true
24805
- ccMax:
24806
- type: integer
24807
- nullable: true
24808
- dupPct:
24809
- type: number
24810
- nullable: true
24811
- maintainabilityBand:
24812
- allOf:
24813
- - $ref: "#/components/schemas/CodeInsightsMaintainabilityBand"
24814
- nullable: true
24815
- badges:
24816
- type: array
24817
- items: { type: string }
24818
- description: >
24819
- Active threshold badges from the latest scan: subset of `god_files`,
24820
- `high_complexity`, `duplication`, `proliferation`, `low_test_ratio`.
24821
- findingsBySeverity:
24822
- $ref: "#/components/schemas/CodeInsightsFindingsBySeverityDto"
24823
- provenance:
24824
- type: object
24825
- additionalProperties:
24826
- $ref: "#/components/schemas/CodeInsightsMetricProvenance"
24827
-
24828
- CodeInsightsRepoListDto:
24829
- allOf:
24830
- - $ref: "#/components/schemas/PageMetaDto"
24831
- - type: object
24832
- required: [items]
24833
- properties:
24834
- items:
24835
- type: array
24836
- items:
24837
- $ref: "#/components/schemas/CodeInsightsRepoListItemDto"
25908
+ maxLength: 500
25909
+ description: JSONPath expression for `json_path_equals`.
24838
25910
 
24839
- CodeInsightsRepoDetailDto:
25911
+ EvalCaseDto:
24840
25912
  type: object
24841
- required:
24842
- [
24843
- repoId,
24844
- repoName,
24845
- language,
24846
- providerSlug,
24847
- webUrl,
24848
- metrics,
24849
- hotspots,
24850
- findings,
24851
- designAnalysis,
24852
- ]
25913
+ additionalProperties: false
25914
+ required: [id, name, input, expectedSignals]
25915
+ description: >
25916
+ One golden case in a suite. 1–20 cases per suite; each case requires ≥1
25917
+ expected signal. When `fixtureCompletion` is set, the worker scores that
25918
+ text without calling a live model (CI/demo path).
24853
25919
  properties:
24854
- repoId:
24855
- type: string
24856
- format: uuid
24857
- repoName:
25920
+ id:
24858
25921
  type: string
24859
- language:
25922
+ minLength: 1
25923
+ maxLength: 64
25924
+ name:
24860
25925
  type: string
24861
- providerSlug:
25926
+ minLength: 1
25927
+ maxLength: 200
25928
+ input:
24862
25929
  type: string
24863
- webUrl:
25930
+ minLength: 1
25931
+ maxLength: 20000
25932
+ description: Case input payload (opaque string; often JSON text).
25933
+ fixtureCompletion:
24864
25934
  type: string
24865
- metrics:
24866
- allOf:
24867
- - $ref: "#/components/schemas/CodeInsightsMetricsDto"
24868
- nullable: true
24869
- description: Null when the repo is pending its first metrics scan.
24870
- hotspots:
24871
- type: array
24872
- items:
24873
- $ref: "#/components/schemas/CodeInsightsHotspotDto"
24874
- findings:
25935
+ maxLength: 100000
25936
+ description: >
25937
+ Optional fixture completion. When present, the worker uses it instead
25938
+ of a live provider call.
25939
+ expectedSignals:
24875
25940
  type: array
25941
+ minItems: 1
25942
+ maxItems: 20
24876
25943
  items:
24877
- $ref: "#/components/schemas/CodeInsightsFindingDto"
24878
- description: >
24879
- Deterministic findings from the latest metrics scan plus LLM findings from the
24880
- latest **succeeded** Design risks run only. Stale LLM rows from older design runs
24881
- are not returned.
24882
- designAnalysis:
24883
- allOf:
24884
- - $ref: "#/components/schemas/CodeInsightsDesignAnalysisDto"
24885
- nullable: true
24886
- description: >
24887
- Latest Design risks run of any status (for UI polling). Null when Design risks
24888
- has never been enqueued for this repo.
25944
+ $ref: "#/components/schemas/EvalExpectedSignalDto"
24889
25945
 
24890
- CodeInsightsDesignAnalysisDto:
25946
+ EvalSuiteTargetDto:
24891
25947
  type: object
24892
- required: [runId, status, finishedAt, errorCode, errorDetail]
25948
+ additionalProperties: false
25949
+ description: >
25950
+ Suite target — at least one of prompt or model. Prompt path requires
25951
+ non-empty `promptBody` (text snapshot) and may include optional `promptKey`
25952
+ slug. Model path requires `provider` + `modelName` (vendor string, same
25953
+ vocabulary as AI Usage `modelName`). Create/update reject when both
25954
+ prompt body is empty and model fields are missing. No separate
25955
+ prompt-template registry in v1; versioning is the suite `version`.
24893
25956
  properties:
24894
- runId:
24895
- type: string
24896
- format: uuid
24897
- status:
25957
+ promptBody:
24898
25958
  type: string
24899
- enum: [queued, running, succeeded, failed, partial_failed]
24900
- finishedAt:
25959
+ maxLength: 100000
25960
+ description: Prompt text snapshot. Empty string allowed only when model fields are set.
25961
+ promptKey:
24901
25962
  type: string
24902
- format: date-time
25963
+ maxLength: 120
24903
25964
  nullable: true
24904
- errorCode:
25965
+ description: Optional slug for the prompt (not a registry foreign key in v1).
25966
+ provider:
24905
25967
  type: string
24906
25968
  nullable: true
24907
- errorDetail:
25969
+ enum: [cursor, claude]
25970
+ description: Model provider; null when suite is prompt-only.
25971
+ modelName:
24908
25972
  type: string
25973
+ maxLength: 200
24909
25974
  nullable: true
25975
+ description: Vendor model id string (aligned with AI Usage `modelName`).
24910
25976
 
24911
- CodeInsightsDesignAnalyzeResponseDto:
25977
+ EvalSuiteDto:
24912
25978
  type: object
24913
- required: [runId]
25979
+ additionalProperties: false
25980
+ required:
25981
+ - id
25982
+ - name
25983
+ - description
25984
+ - version
25985
+ - createdAt
25986
+ - updatedAt
25987
+ - createdByUserId
25988
+ - target
25989
+ - cases
25990
+ description: >
25991
+ Latest version of a workspace eval suite. Max 50 suites per workspace.
25992
+ Name 1–120 chars; description ≤ 2000; version starts at 1.
24914
25993
  properties:
24915
- runId:
25994
+ id:
24916
25995
  type: string
24917
25996
  format: uuid
24918
- description: Enqueued Design risks run id (`tai_workspace_readiness_runs.id`).
25997
+ name:
25998
+ type: string
25999
+ minLength: 1
26000
+ maxLength: 120
26001
+ description:
26002
+ type: string
26003
+ maxLength: 2000
26004
+ version:
26005
+ type: integer
26006
+ minimum: 1
26007
+ description: Monotonic suite version; bumps when target/cases/promptBody change.
26008
+ createdAt:
26009
+ type: string
26010
+ format: date-time
26011
+ updatedAt:
26012
+ type: string
26013
+ format: date-time
26014
+ createdByUserId:
26015
+ type: string
26016
+ format: uuid
26017
+ target:
26018
+ $ref: "#/components/schemas/EvalSuiteTargetDto"
26019
+ cases:
26020
+ type: array
26021
+ minItems: 1
26022
+ maxItems: 20
26023
+ items:
26024
+ $ref: "#/components/schemas/EvalCaseDto"
24919
26025
 
24920
- CodeInsightsOrgHotspotDto:
24921
- allOf:
24922
- - $ref: "#/components/schemas/CodeInsightsHotspotDto"
24923
- - type: object
24924
- required: [repoId, repoName]
24925
- properties:
24926
- repoId:
24927
- type: string
24928
- format: uuid
24929
- repoName:
24930
- type: string
26026
+ EvalSuiteListDto:
26027
+ type: object
26028
+ additionalProperties: false
26029
+ required: [suites]
26030
+ properties:
26031
+ suites:
26032
+ type: array
26033
+ maxItems: 50
26034
+ items:
26035
+ $ref: "#/components/schemas/EvalSuiteDto"
24931
26036
 
24932
- CodeInsightsSonarDto:
26037
+ CreateEvalSuiteBodyDto:
24933
26038
  type: object
24934
- required: [connected]
26039
+ additionalProperties: false
26040
+ required: [name, target, cases]
24935
26041
  properties:
24936
- connected:
24937
- type: boolean
24938
- description: Whether a SonarQube source is configured for the workspace.
24939
- coveragePct:
24940
- type: number
24941
- nullable: true
24942
- description: Org-level SonarQube coverage from the latest precomputed quality snapshot.
24943
- techDebtRatioPct:
24944
- type: number
24945
- nullable: true
24946
- description: Org-level SonarQube SQALE technical debt ratio from the latest quality snapshot.
26042
+ name:
26043
+ type: string
26044
+ minLength: 1
26045
+ maxLength: 120
26046
+ description:
26047
+ type: string
26048
+ maxLength: 2000
26049
+ default: ""
26050
+ target:
26051
+ $ref: "#/components/schemas/EvalSuiteTargetDto"
26052
+ cases:
26053
+ type: array
26054
+ minItems: 1
26055
+ maxItems: 20
26056
+ items:
26057
+ $ref: "#/components/schemas/EvalCaseDto"
24947
26058
 
24948
- CodeInsightsSummaryDto:
26059
+ UpdateEvalSuiteBodyDto:
24949
26060
  type: object
24950
- required: [reposMeasured, reposPending, findingsBySeverity, topHotspots, sonar]
26061
+ additionalProperties: false
26062
+ required: [name, target, cases]
26063
+ description: >
26064
+ Full replace of mutable suite fields. Version bumps only when `target`,
26065
+ `cases`, or `promptBody` change versus the stored latest version.
24951
26066
  properties:
24952
- reposMeasured:
24953
- type: integer
24954
- minimum: 0
24955
- description: Active repos whose latest metrics scan completed (`ok`).
24956
- reposPending:
24957
- type: integer
24958
- minimum: 0
24959
- description: Active repos without a completed metrics scan (never scanned, or only failed/skipped).
24960
- ccAvgMedian:
24961
- type: number
24962
- nullable: true
24963
- description: Unweighted median of latest `ccAvg` across measured repos (null when none measured).
24964
- dupPctMedian:
24965
- type: number
24966
- nullable: true
24967
- description: Unweighted median of latest `dupPct` across measured repos (null when none measured).
24968
- findingsBySeverity:
24969
- $ref: "#/components/schemas/CodeInsightsFindingsBySeverityDto"
24970
- topHotspots:
26067
+ name:
26068
+ type: string
26069
+ minLength: 1
26070
+ maxLength: 120
26071
+ description:
26072
+ type: string
26073
+ maxLength: 2000
26074
+ default: ""
26075
+ target:
26076
+ $ref: "#/components/schemas/EvalSuiteTargetDto"
26077
+ cases:
24971
26078
  type: array
26079
+ minItems: 1
26080
+ maxItems: 20
24972
26081
  items:
24973
- $ref: "#/components/schemas/CodeInsightsOrgHotspotDto"
24974
- description: Org top-10 complexity hotspots by `ccMax` (current per-repo snapshots).
24975
- sonar:
24976
- $ref: "#/components/schemas/CodeInsightsSonarDto"
26082
+ $ref: "#/components/schemas/EvalCaseDto"
24977
26083
 
24978
- InsightsTestPyramidMaturityDto:
26084
+ EvalRunStatusDto:
24979
26085
  type: string
24980
- enum: [missing, emerging, established, mature]
24981
- description: >
24982
- Presence maturity (model A) using count-based layer presence
24983
- (`fileCount > 0`), not AF signal-inclusive `present`.
26086
+ enum: [queued, running, succeeded, failed, cancelled]
24984
26087
 
24985
- InsightsTestPyramidShapeLabelDto:
26088
+ EvalCaseResultStatusDto:
24986
26089
  type: string
24987
- enum: [insufficient_data, base_heavy, balanced, top_heavy, middle_heavy]
24988
26090
  description: >
24989
- Advisory shape label vs fixed 70/20/10. `insufficient_data` when total
24990
- classified test files < 10 (band percents are null).
26091
+ Per-case outcome. `error` is used when completion is unavailable
26092
+ (`code: completion_unavailable`) or another non-score failure occurs.
26093
+ enum: [passed, failed, error]
24991
26094
 
24992
- InsightsTestPyramidShapeDto:
26095
+ EvalCaseResultDto:
24993
26096
  type: object
24994
- required: [label, totalClassifiedFiles, basePercent, middlePercent, topPercent, targets]
26097
+ additionalProperties: false
26098
+ required:
26099
+ - caseId
26100
+ - name
26101
+ - status
26102
+ - pass
26103
+ - failedSignalIds
26104
+ description: >
26105
+ Persisted result for one case. `pass` is true only when `status` is
26106
+ `passed` (all expected signals matched). On signal failure, `pass` is
26107
+ false and `failedSignalIds` lists the failing signal ids. On
26108
+ `completion_unavailable`, `status` is `error` and `code` is set.
24995
26109
  properties:
24996
- label:
24997
- $ref: "#/components/schemas/InsightsTestPyramidShapeLabelDto"
24998
- totalClassifiedFiles:
26110
+ caseId:
26111
+ type: string
26112
+ name:
26113
+ type: string
26114
+ status:
26115
+ $ref: "#/components/schemas/EvalCaseResultStatusDto"
26116
+ pass:
26117
+ type: boolean
26118
+ failedSignalIds:
26119
+ type: array
26120
+ items:
26121
+ type: string
26122
+ completion:
26123
+ type: string
26124
+ nullable: true
26125
+ description: Completion text used for scoring (fixture or live).
26126
+ inputTokens:
24999
26127
  type: integer
26128
+ nullable: true
25000
26129
  minimum: 0
25001
- description: Sum of classified test **files** across the five layers (not test cases).
25002
- basePercent:
25003
- type: number
26130
+ outputTokens:
26131
+ type: integer
25004
26132
  nullable: true
25005
- description: Share of classified files in unit (base). Null when insufficient_data.
25006
- middlePercent:
26133
+ minimum: 0
26134
+ costCents:
25007
26135
  type: number
25008
26136
  nullable: true
26137
+ minimum: 0
26138
+ description: Provider-reported cost in cents when available.
26139
+ code:
26140
+ type: string
26141
+ nullable: true
25009
26142
  description: >
25010
- Share in integration + contract + acceptance_bdd (middle). Null when
25011
- insufficient_data.
25012
- topPercent:
25013
- type: number
26143
+ Machine-readable error when `status` is `error`
26144
+ (e.g. `completion_unavailable`).
26145
+ error:
26146
+ type: string
25014
26147
  nullable: true
25015
- description: Share in e2e (top). Null when insufficient_data.
25016
- targets:
25017
- type: object
25018
- required: [basePercent, middlePercent, topPercent]
25019
- properties:
25020
- basePercent: { type: number, enum: [70] }
25021
- middlePercent: { type: number, enum: [20] }
25022
- topPercent: { type: number, enum: [10] }
25023
-
25024
- InsightsTestPyramidLayerCountsDto:
25025
- type: object
25026
- required: [unit, integration, acceptance_bdd, contract, e2e]
25027
- properties:
25028
- unit: { type: integer, minimum: 0 }
25029
- integration: { type: integer, minimum: 0 }
25030
- acceptance_bdd: { type: integer, minimum: 0 }
25031
- contract: { type: integer, minimum: 0 }
25032
- e2e: { type: integer, minimum: 0 }
26148
+ description: Human-readable error detail when `status` is `error`.
25033
26149
 
25034
- InsightsTestPyramidLayerPresentDto:
26150
+ EvalSuiteSnapshotDto:
25035
26151
  type: object
25036
- required: [unit, integration, acceptance_bdd, contract, e2e]
26152
+ additionalProperties: false
26153
+ required: [name, description, version, target, cases]
26154
+ description: >
26155
+ Immutable suite snapshot pinned on a run (`suiteVersion` + JSON). Used so
26156
+ historical runs stay interpretable after later suite edits.
25037
26157
  properties:
25038
- unit: { type: boolean }
25039
- integration: { type: boolean }
25040
- acceptance_bdd: { type: boolean }
25041
- contract: { type: boolean }
25042
- e2e: { type: boolean }
26158
+ name:
26159
+ type: string
26160
+ description:
26161
+ type: string
26162
+ version:
26163
+ type: integer
26164
+ minimum: 1
26165
+ target:
26166
+ $ref: "#/components/schemas/EvalSuiteTargetDto"
26167
+ cases:
26168
+ type: array
26169
+ items:
26170
+ $ref: "#/components/schemas/EvalCaseDto"
25043
26171
 
25044
- InsightsTestPyramidLayerPresenceDto:
26172
+ EvalRunDto:
25045
26173
  type: object
25046
- required: [presentRepos, applicableRepos, percent, missingRepoIds, missingRepoNames]
26174
+ additionalProperties: false
26175
+ required:
26176
+ - id
26177
+ - suiteId
26178
+ - suiteVersion
26179
+ - status
26180
+ - startedAt
26181
+ - finishedAt
26182
+ - passCount
26183
+ - failCount
26184
+ - errorCount
26185
+ - score
26186
+ - caseResults
26187
+ description: >
26188
+ Persisted eval run. Suite score = `passedCases / scoredCases` in [0,1]
26189
+ when at least one case was scored; `null` when the run ends with all
26190
+ cases in `error` (status `failed`). List endpoints return at most the
26191
+ last 50 runs per suite.
25047
26192
  properties:
25048
- presentRepos: { type: integer, minimum: 0 }
25049
- applicableRepos: { type: integer, minimum: 0 }
25050
- percent:
26193
+ id:
26194
+ type: string
26195
+ format: uuid
26196
+ suiteId:
26197
+ type: string
26198
+ format: uuid
26199
+ suiteVersion:
25051
26200
  type: integer
26201
+ minimum: 1
26202
+ status:
26203
+ $ref: "#/components/schemas/EvalRunStatusDto"
26204
+ startedAt:
26205
+ type: string
26206
+ format: date-time
26207
+ nullable: true
26208
+ description: Set when the worker claims the run (`running`).
26209
+ finishedAt:
26210
+ type: string
26211
+ format: date-time
25052
26212
  nullable: true
26213
+ passCount:
26214
+ type: integer
25053
26215
  minimum: 0
25054
- maximum: 100
25055
- missingRepoIds:
25056
- type: array
25057
- items: { type: string, format: uuid }
25058
- missingRepoNames:
25059
- type: array
25060
- items: { type: string }
25061
-
25062
- InsightsTestPyramidGapRepoDto:
25063
- type: object
25064
- required: [repoId, repoName]
25065
- properties:
25066
- repoId: { type: string, format: uuid }
25067
- repoName: { type: string }
25068
-
25069
- InsightsTestPyramidGapsByLayerDto:
25070
- type: object
25071
- required: [unit, integration, acceptance_bdd, contract, e2e]
25072
- properties:
25073
- unit:
25074
- type: array
25075
- items: { $ref: "#/components/schemas/InsightsTestPyramidGapRepoDto" }
25076
- integration:
25077
- type: array
25078
- items: { $ref: "#/components/schemas/InsightsTestPyramidGapRepoDto" }
25079
- acceptance_bdd:
25080
- type: array
25081
- items: { $ref: "#/components/schemas/InsightsTestPyramidGapRepoDto" }
25082
- contract:
25083
- type: array
25084
- items: { $ref: "#/components/schemas/InsightsTestPyramidGapRepoDto" }
25085
- e2e:
26216
+ failCount:
26217
+ type: integer
26218
+ minimum: 0
26219
+ errorCount:
26220
+ type: integer
26221
+ minimum: 0
26222
+ score:
26223
+ type: number
26224
+ nullable: true
26225
+ minimum: 0
26226
+ maximum: 1
26227
+ description: >
26228
+ `passedCases / scoredCases` in [0,1], or null when no case was scored
26229
+ (all-error run).
26230
+ caseResults:
25086
26231
  type: array
25087
- items: { $ref: "#/components/schemas/InsightsTestPyramidGapRepoDto" }
25088
-
25089
- InsightsTestPyramidMaturityCountsDto:
25090
- type: object
25091
- required: [missing, emerging, established, mature]
25092
- properties:
25093
- missing: { type: integer, minimum: 0 }
25094
- emerging: { type: integer, minimum: 0 }
25095
- established: { type: integer, minimum: 0 }
25096
- mature: { type: integer, minimum: 0 }
25097
-
25098
- InsightsTestPyramidLayerPresenceMapDto:
25099
- type: object
25100
- required: [unit, integration, acceptance_bdd, contract, e2e]
25101
- properties:
25102
- unit: { $ref: "#/components/schemas/InsightsTestPyramidLayerPresenceDto" }
25103
- integration: { $ref: "#/components/schemas/InsightsTestPyramidLayerPresenceDto" }
25104
- acceptance_bdd: { $ref: "#/components/schemas/InsightsTestPyramidLayerPresenceDto" }
25105
- contract: { $ref: "#/components/schemas/InsightsTestPyramidLayerPresenceDto" }
25106
- e2e: { $ref: "#/components/schemas/InsightsTestPyramidLayerPresenceDto" }
25107
-
25108
- InsightsTestPyramidMaturityDeltaDto:
25109
- type: string
25110
- enum: [up, down, unchanged, none]
25111
- description: >
25112
- Insights maturity rank change vs the immediately previous pyramid point
25113
- (missing 0, emerging 1, established 2, mature 3). `none` when the repo
25114
- has no previous succeeded/partial_failed/failed point.
26232
+ items:
26233
+ $ref: "#/components/schemas/EvalCaseResultDto"
26234
+ suiteSnapshot:
26235
+ type: object
26236
+ nullable: true
26237
+ allOf:
26238
+ - $ref: "#/components/schemas/EvalSuiteSnapshotDto"
26239
+ description: Pinned suite snapshot for this run (present on persisted runs).
25115
26240
 
25116
- InsightsTestPyramidConfidenceDto:
25117
- type: string
25118
- enum: [high, medium, low]
26241
+ EvalRunListDto:
26242
+ type: object
26243
+ additionalProperties: false
26244
+ required: [runs]
26245
+ properties:
26246
+ runs:
26247
+ type: array
26248
+ maxItems: 50
26249
+ items:
26250
+ $ref: "#/components/schemas/EvalRunDto"
25119
26251
 
25120
- InsightsTestPyramidLayerConfidenceDto:
26252
+ EvalRunEnqueueResponseDto:
25121
26253
  type: object
25122
- required: [unit, integration, acceptance_bdd, contract, e2e]
26254
+ additionalProperties: false
26255
+ required: [runId, status]
25123
26256
  properties:
25124
- unit: { $ref: "#/components/schemas/InsightsTestPyramidConfidenceDto" }
25125
- integration: { $ref: "#/components/schemas/InsightsTestPyramidConfidenceDto" }
25126
- acceptance_bdd: { $ref: "#/components/schemas/InsightsTestPyramidConfidenceDto" }
25127
- contract: { $ref: "#/components/schemas/InsightsTestPyramidConfidenceDto" }
25128
- e2e: { $ref: "#/components/schemas/InsightsTestPyramidConfidenceDto" }
26257
+ runId:
26258
+ type: string
26259
+ format: uuid
26260
+ status:
26261
+ type: string
26262
+ enum: [queued]
26263
+ description: Always `queued` on enqueue; poll GET run for progress.
25129
26264
 
25130
- InsightsTestPyramidCoverageRollupDto:
26265
+ EvalRegressionDto:
25131
26266
  type: object
25132
- required: [reposWithCoverage, medianLinePercent]
26267
+ additionalProperties: false
26268
+ required:
26269
+ - suiteId
26270
+ - suiteVersion
26271
+ - priorScore
26272
+ - currentScore
26273
+ - scoreDrop
26274
+ description: >
26275
+ Regression when prior score − current score ≥ 0.10 on the same
26276
+ suiteId+suiteVersion case set, or suite score drop ≥ 0.10.
25133
26277
  properties:
25134
- reposWithCoverage:
26278
+ suiteId:
26279
+ type: string
26280
+ format: uuid
26281
+ suiteName:
26282
+ type: string
26283
+ suiteVersion:
25135
26284
  type: integer
25136
- minimum: 0
25137
- description: Repos whose overlaid `lineCoverage` is non-null.
25138
- medianLinePercent:
25139
- type: number
26285
+ minimum: 1
26286
+ caseId:
26287
+ type: string
26288
+ nullable: true
26289
+ description: Set for case-level regressions; null for suite-level score drops.
26290
+ caseName:
26291
+ type: string
25140
26292
  nullable: true
26293
+ priorRunId:
26294
+ type: string
26295
+ format: uuid
26296
+ currentRunId:
26297
+ type: string
26298
+ format: uuid
26299
+ priorScore:
26300
+ type: number
25141
26301
  minimum: 0
25142
- maximum: 100
25143
- description: >
25144
- Median of repo `linePercent` among repos that have coverage. Null when
25145
- `reposWithCoverage` is 0.
25146
-
25147
- InsightsTestPyramidCiQualityDto:
25148
- type: object
25149
- nullable: true
25150
- required: [ciFailureRatePercent, bucketEnd]
25151
- properties:
25152
- ciFailureRatePercent:
26302
+ maximum: 1
26303
+ currentScore:
25153
26304
  type: number
25154
26305
  minimum: 0
25155
- maximum: 100
25156
- description: >
25157
- Latest org dashboard `quality.ciFailureRatePercent`, falling back to
25158
- `quality.ciBuildFailRatePercent`.
25159
- ciFlakinessPercent:
26306
+ maximum: 1
26307
+ scoreDrop:
25160
26308
  type: number
25161
26309
  minimum: 0
25162
- maximum: 100
25163
- description: Included only when `quality.ciFlakinessPercent` is a finite number.
25164
- bucketEnd:
25165
- type: string
25166
- description: Dashboard metrics bucket end for the org snapshot.
26310
+ maximum: 1
26311
+ description: priorScore − currentScore (always ≥ 0.10 for listed items).
25167
26312
 
25168
- InsightsTestPyramidSummaryDto:
26313
+ EvalPromptTipDto:
25169
26314
  type: object
25170
- required:
25171
- - workspaceId
25172
- - generatedAt
25173
- - reposWithPyramid
25174
- - reposFromDegradedRuns
25175
- - totalClassifiedFiles
25176
- - shape
25177
- - layerPresence
25178
- - maturityCounts
25179
- - gapsByLayer
25180
- - newestScannedAt
25181
- - maturedRepoCount
25182
- - slippedRepoCount
25183
- - previousShape
25184
- - coverage
25185
- - e2eCrossRepoCandidateCount
25186
- - reposWithHotspots
25187
- - ciQuality
26315
+ additionalProperties: false
26316
+ required: [suiteId, message]
26317
+ description: Tip derived from failed signal notes / case names on recent runs.
25188
26318
  properties:
25189
- workspaceId: { type: string, format: uuid }
25190
- generatedAt: { type: string, format: date-time }
25191
- reposWithPyramid: { type: integer, minimum: 0 }
25192
- reposFromDegradedRuns:
25193
- type: array
25194
- items: { type: string, format: uuid }
25195
- description: Repos whose newest pyramid came from a non-succeeded readiness run.
25196
- totalClassifiedFiles:
25197
- type: integer
25198
- minimum: 0
25199
- description: Workspace sum of classified test files (not cases).
25200
- shape:
25201
- $ref: "#/components/schemas/InsightsTestPyramidShapeDto"
25202
- layerPresence:
25203
- $ref: "#/components/schemas/InsightsTestPyramidLayerPresenceMapDto"
25204
- maturityCounts:
25205
- $ref: "#/components/schemas/InsightsTestPyramidMaturityCountsDto"
25206
- gapsByLayer:
25207
- $ref: "#/components/schemas/InsightsTestPyramidGapsByLayerDto"
25208
- newestScannedAt:
26319
+ suiteId:
26320
+ type: string
26321
+ format: uuid
26322
+ suiteName:
26323
+ type: string
26324
+ caseId:
25209
26325
  type: string
25210
- format: date-time
25211
26326
  nullable: true
25212
- description: Latest per-repo `scannedAt`. Null when `reposWithPyramid` is 0.
25213
- maturedRepoCount:
25214
- type: integer
25215
- minimum: 0
25216
- description: Repos whose Insights maturity rank increased vs the previous point.
25217
- slippedRepoCount:
25218
- type: integer
26327
+ caseName:
26328
+ type: string
26329
+ nullable: true
26330
+ signalId:
26331
+ type: string
26332
+ nullable: true
26333
+ message:
26334
+ type: string
26335
+ maxLength: 2000
26336
+
26337
+ EvalTokenEfficiencyDto:
26338
+ type: object
26339
+ additionalProperties: false
26340
+ required: [avgInputTokens, avgOutputTokens, avgCostCents]
26341
+ description: >
26342
+ Averages over successful cases in the last succeeded run per suite
26343
+ (workspace rollup). Nullables when token/cost fields were not returned.
26344
+ properties:
26345
+ avgInputTokens:
26346
+ type: number
26347
+ nullable: true
25219
26348
  minimum: 0
25220
- description: Repos whose Insights maturity rank decreased vs the previous point.
25221
- previousShape:
25222
- allOf:
25223
- - $ref: "#/components/schemas/InsightsTestPyramidShapeDto"
26349
+ avgOutputTokens:
26350
+ type: number
25224
26351
  nullable: true
25225
- description: >
25226
- Insights workspace shape from previous-point file totals for repos that
25227
- have a previous point. Null when no repo has a previous point.
25228
- coverage:
25229
- $ref: "#/components/schemas/InsightsTestPyramidCoverageRollupDto"
25230
- e2eCrossRepoCandidateCount:
25231
- type: integer
25232
26352
  minimum: 0
25233
- reposWithHotspots:
25234
- type: integer
26353
+ avgCostCents:
26354
+ type: number
26355
+ nullable: true
25235
26356
  minimum: 0
25236
- description: Repos whose latest Code Insights snapshot has `hotspotCount` > 0.
25237
- ciQuality:
25238
- $ref: "#/components/schemas/InsightsTestPyramidCiQualityDto"
25239
26357
 
25240
- InsightsTestPyramidRepoItemDto:
26358
+ EvalModelComparisonDto:
25241
26359
  type: object
25242
- required:
25243
- - repoId
25244
- - repoName
25245
- - scannedAt
25246
- - currentRunStatus
25247
- - maturity
25248
- - layerFileCounts
25249
- - layerPresent
25250
- - totalClassifiedFiles
25251
- - shape
25252
- - previousMaturity
25253
- - maturityDelta
25254
- - previousShapeLabel
25255
- - lineCoverage
25256
- - lowestConfidence
25257
- - layerConfidence
25258
- - evidenceCount
25259
- - frameworks
25260
- - layerApplicable
25261
- - e2eCrossRepoCandidate
25262
- - hotspotCount
26360
+ additionalProperties: false
26361
+ required: [provider, modelName, suiteCount, avgScore]
25263
26362
  properties:
25264
- repoId: { type: string, format: uuid }
25265
- repoName: { type: string }
25266
- scannedAt: { type: string, format: date-time }
25267
- currentRunStatus:
25268
- $ref: "#/components/schemas/TestPyramidRunStatusDto"
25269
- maturity:
25270
- $ref: "#/components/schemas/InsightsTestPyramidMaturityDto"
25271
- previousMaturity:
25272
- allOf:
25273
- - $ref: "#/components/schemas/InsightsTestPyramidMaturityDto"
25274
- nullable: true
25275
- maturityDelta:
25276
- $ref: "#/components/schemas/InsightsTestPyramidMaturityDeltaDto"
25277
- previousShapeLabel:
25278
- allOf:
25279
- - $ref: "#/components/schemas/InsightsTestPyramidShapeLabelDto"
25280
- nullable: true
25281
- layerFileCounts:
25282
- $ref: "#/components/schemas/InsightsTestPyramidLayerCountsDto"
25283
- layerPresent:
25284
- $ref: "#/components/schemas/InsightsTestPyramidLayerPresentDto"
25285
- layerApplicable:
25286
- allOf:
25287
- - $ref: "#/components/schemas/InsightsTestPyramidLayerPresentDto"
25288
- description: Snapshot `layers.*.applicable` for each layer.
25289
- totalClassifiedFiles: { type: integer, minimum: 0 }
25290
- shape:
25291
- $ref: "#/components/schemas/InsightsTestPyramidShapeDto"
25292
- lineCoverage:
25293
- allOf:
25294
- - $ref: "#/components/schemas/TestPyramidLineCoverageDto"
25295
- description: >
25296
- Same overlay as AF progress — latest Sonar row first, else snapshot
25297
- `testPyramid.lineCoverage`. Null when both are missing. Not Code Insights
25298
- `coveragePct`.
25299
- lowestConfidence:
25300
- allOf:
25301
- - $ref: "#/components/schemas/InsightsTestPyramidConfidenceDto"
25302
- description: >
25303
- Minimum confidence among layers with Insights presence (`fileCount > 0`);
25304
- if none present, minimum of applicable layers. Order low < medium < high.
25305
- layerConfidence:
25306
- $ref: "#/components/schemas/InsightsTestPyramidLayerConfidenceDto"
25307
- evidenceCount:
26363
+ provider:
26364
+ $ref: "#/components/schemas/EvalAiProviderDto"
26365
+ modelName:
26366
+ type: string
26367
+ suiteCount:
25308
26368
  type: integer
25309
26369
  minimum: 0
25310
- description: Sum of layer `evidence[]` lengths on the latest snapshot.
25311
- frameworks:
25312
- type: array
25313
- maxItems: 8
25314
- items: { type: string }
25315
- description: Unique framework names across layers, capped at 8.
25316
- e2eCrossRepoCandidate: { type: boolean }
25317
- hotspotCount:
25318
- type: integer
26370
+ avgScore:
26371
+ type: number
25319
26372
  nullable: true
25320
26373
  minimum: 0
25321
- description: >
25322
- Row count in `tai_workspace_repo_code_hotspots` for the repo's latest
25323
- Code Insights metrics snapshot. Null when the repo has no metrics snapshot.
26374
+ maximum: 1
26375
+ description: Average suite score across succeeded runs for this model; null when none.
25324
26376
 
25325
- InsightsTestPyramidRepoListDto:
26377
+ EvalInsightsDto:
25326
26378
  type: object
25327
- required: [items, total, limit, offset]
26379
+ additionalProperties: false
26380
+ required: [regressions, promptTips, tokenEfficiency, modelComparison]
26381
+ description: >
26382
+ Insights hub payload for Prompt & model evals. Empty succeeded-run history
26383
+ → empty arrays and null `tokenEfficiency`.
25328
26384
  properties:
25329
- items:
26385
+ regressions:
25330
26386
  type: array
25331
26387
  items:
25332
- $ref: "#/components/schemas/InsightsTestPyramidRepoItemDto"
25333
- total: { type: integer, minimum: 0 }
25334
- limit: { type: integer, minimum: 1 }
25335
- offset: { type: integer, minimum: 0 }
26388
+ $ref: "#/components/schemas/EvalRegressionDto"
26389
+ promptTips:
26390
+ type: array
26391
+ items:
26392
+ $ref: "#/components/schemas/EvalPromptTipDto"
26393
+ tokenEfficiency:
26394
+ type: object
26395
+ nullable: true
26396
+ allOf:
26397
+ - $ref: "#/components/schemas/EvalTokenEfficiencyDto"
26398
+ modelComparison:
26399
+ type: array
26400
+ items:
26401
+ $ref: "#/components/schemas/EvalModelComparisonDto"