@shipeasy/openapi 2.4.0 → 2.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/openapi.json CHANGED
@@ -113,6 +113,11 @@
113
113
  "parent": "Ops",
114
114
  "description": "Comments on a queue item — the discussion thread that hangs off any bug,\nfeature request, or auto-filed error/alert ticket. Append a comment or read\nthe thread; one level of threaded replies via `parentId`.\n\n**Mentions.** `@teammate` in a body raises an in-app notification for that\nperson; `@shipeasy` asks Jarvis (the AI agent) to read the item and reply.\nComments authored by Jarvis carry `authorType: system`."
115
115
  },
116
+ {
117
+ "name": "Investigations",
118
+ "parent": "Ops",
119
+ "description": "Investigation records on a queue item — the structured, read-only write-ups\nan AI agent produces while working it (findings / a blocking question / QA\nnotes), plus the `working` run rows an ack or an AI hand-off opens. This is\nthe AI-write seam the cockpit's detail panel renders: `list` reads what a\nprevious run found, `create` appends a new record, and `update` fills in the\n`working` run record you were handed (findings, PR, confidence) as you work."
120
+ },
116
121
  {
117
122
  "name": "Projects",
118
123
  "description": "Projects: the account-level container every other resource is scoped to.\n\n**Account-level, not bound-project-level.** Both operations resolve from the caller's credential rather than the `.shipeasy`-bound project — `current` reads the project the auth header maps to, and `upsert` find-or-creates under the session's owner. Neither touches the local `.shipeasy` binding; recording the result there is a consumer side-effect layered on top.\n\n**Idempotent upsert.** A project is keyed by `(owner_email, domain)`. Calling `upsert` again with the same domain returns the existing project with `created: false`, so it is safe to run on every install."
@@ -2544,7 +2549,7 @@
2544
2549
  "post": {
2545
2550
  "operationId": "createConfig",
2546
2551
  "summary": "Create a dynamic config",
2547
- "description": "Creates a new config with the given `schema`. The initial `value` (or an empty object) is published as version 1 on **every** env.\n\nReturns `409` if `name` already exists in the project, `400` if `value` doesn't validate against `schema`.\n\n**Use cases**\n\n- **Minimal create** — `name` + `schema`. Initial value defaults to `{}`.\n- **Seeded create** — supply a flat `value` to publish the same object on every env.\n- **Per-env seed** — supply a `{ env: value }` map for different per-env starting values.",
2552
+ "description": "Creates a new config with the given `schema`. The initial `value` (or an empty object) is published as version 1 on **every** env.\n\nReturns `409` if `name` already exists in the project, `400` if `value` doesn't validate against `schema`.\n\n**Use cases**\n\n- **Minimal create** — `name` + `schema`. Initial value defaults to `{}`.\n- **Seeded create** — supply a flat `value` to publish the same object on every env.\n- **Per-env seed** — supply a `{ env: value }` map under `value`, or pass the env keys `dev`/`staging`/`prod` directly (each overrides `value` for that env and is published at version 1).",
2548
2553
  "tags": [
2549
2554
  "Configs"
2550
2555
  ],
@@ -2609,8 +2614,8 @@
2609
2614
  }
2610
2615
  },
2611
2616
  "perEnvSeed": {
2612
- "summary": "Per-env seed",
2613
- "description": "Pass a `{ env: value }` map to seed different initial values per env.",
2617
+ "summary": "Per-env seed (env keys)",
2618
+ "description": "Pass the env keys directly to seed different initial values per env. Each overrides `value` for that env and is published at version 1.",
2614
2619
  "value": {
2615
2620
  "name": "pricing.tiers",
2616
2621
  "schema": {
@@ -2624,40 +2629,28 @@
2624
2629
  "tiers"
2625
2630
  ]
2626
2631
  },
2627
- "value": {
2628
- "dev": {
2629
- "tiers": [
2630
- {
2631
- "name": "free"
2632
- },
2633
- {
2634
- "name": "pro"
2635
- },
2636
- {
2637
- "name": "enterprise"
2638
- }
2639
- ]
2640
- },
2641
- "stage": {
2642
- "tiers": [
2643
- {
2644
- "name": "free"
2645
- },
2646
- {
2647
- "name": "pro"
2648
- }
2649
- ]
2650
- },
2651
- "prod": {
2652
- "tiers": [
2653
- {
2654
- "name": "free"
2655
- },
2656
- {
2657
- "name": "pro"
2658
- }
2659
- ]
2660
- }
2632
+ "dev": {
2633
+ "tiers": [
2634
+ {
2635
+ "name": "free"
2636
+ },
2637
+ {
2638
+ "name": "pro"
2639
+ },
2640
+ {
2641
+ "name": "enterprise"
2642
+ }
2643
+ ]
2644
+ },
2645
+ "prod": {
2646
+ "tiers": [
2647
+ {
2648
+ "name": "free"
2649
+ },
2650
+ {
2651
+ "name": "pro"
2652
+ }
2653
+ ]
2661
2654
  }
2662
2655
  }
2663
2656
  }
@@ -2901,7 +2894,7 @@
2901
2894
  "patch": {
2902
2895
  "operationId": "updateConfig",
2903
2896
  "summary": "Update a dynamic config",
2904
- "description": "Partial update. When `value` is supplied it is **republished on every env** (new version per env). When `schema` is supplied it replaces the current schema; every existing value is re-validated.\n\nFor env-scoped edits, use the draft/publish flow (`PUT /{id}/drafts` then `POST /{id}/publish`) instead.\n\n**Use cases**\n\n- **Republish flat value** — `{ \"value\": {…} }` sets the same value on every env.\n- **Schema migration** — `{ \"schema\": {…} }` replaces the schema; existing values are re-validated.\n- **Env-scoped edits** — use `PUT /{id}/drafts` + `POST /{id}/publish` instead of PATCH.",
2897
+ "description": "Partial update. When `value` is supplied it is **republished on every env** (new version per env). A per-env key (`dev`/`staging`/`prod`) publishes a new version to **only that env**, immediately, overriding `value` for it. When `schema` is supplied it replaces the current schema; every existing value is re-validated.\n\n**Use cases**\n\n- **Republish flat value** — `{ \"value\": {…} }` sets the same value on every env.\n- **Publish one env** — `{ \"prod\": {…} }` publishes a new version to prod only, instantly.\n- **Schema migration** — `{ \"schema\": {…} }` replaces the schema; existing values are re-validated.",
2905
2898
  "tags": [
2906
2899
  "Configs"
2907
2900
  ],
@@ -2943,6 +2936,25 @@
2943
2936
  }
2944
2937
  }
2945
2938
  },
2939
+ "prodOnly": {
2940
+ "summary": "Per-env — publish prod only",
2941
+ "description": "Publishes a new version to prod only, immediately. dev/staging untouched.",
2942
+ "value": {
2943
+ "prod": {
2944
+ "tiers": [
2945
+ {
2946
+ "name": "free"
2947
+ },
2948
+ {
2949
+ "name": "pro"
2950
+ },
2951
+ {
2952
+ "name": "enterprise"
2953
+ }
2954
+ ]
2955
+ }
2956
+ }
2957
+ },
2946
2958
  "schemaOnly": {
2947
2959
  "summary": "Schema-only update",
2948
2960
  "description": "Replaces the schema. Existing values must still validate or the update fails.",
@@ -3181,6 +3193,7 @@
3181
3193
  ],
3182
3194
  "x-cli": {
3183
3195
  "name": "draft",
3196
+ "hidden": true,
3184
3197
  "positional": [
3185
3198
  "id"
3186
3199
  ]
@@ -3267,6 +3280,7 @@
3267
3280
  ],
3268
3281
  "x-cli": {
3269
3282
  "name": "discard-draft",
3283
+ "hidden": true,
3270
3284
  "positional": [
3271
3285
  "id"
3272
3286
  ]
@@ -3366,6 +3380,7 @@
3366
3380
  ],
3367
3381
  "x-cli": {
3368
3382
  "name": "publish",
3383
+ "hidden": true,
3369
3384
  "positional": [
3370
3385
  "id"
3371
3386
  ]
@@ -3457,6 +3472,7 @@
3457
3472
  ],
3458
3473
  "x-cli": {
3459
3474
  "name": "activity",
3475
+ "hidden": true,
3460
3476
  "positional": [
3461
3477
  "id"
3462
3478
  ]
@@ -3663,6 +3679,7 @@
3663
3679
  ],
3664
3680
  "x-cli": {
3665
3681
  "name": "versions",
3682
+ "hidden": true,
3666
3683
  "positional": [
3667
3684
  "id"
3668
3685
  ]
@@ -7545,7 +7562,7 @@
7545
7562
  "summary": "List an item's investigation records",
7546
7563
  "description": "The structured, read-only investigation records on a queue item — the\nfindings / blocking questions / QA notes an AI agent posted while working\nit, plus its `working` run rows. Returns `published` records only, newest\nfirst (max 50).\n\n**Use case:** Read what a previous agent run already found before starting\nyour own investigation of the item.",
7547
7564
  "tags": [
7548
- "Ops"
7565
+ "Investigations"
7549
7566
  ],
7550
7567
  "parameters": [
7551
7568
  {
@@ -7593,14 +7610,20 @@
7593
7610
  "UNAUTHORIZED",
7594
7611
  "FORBIDDEN",
7595
7612
  "NOT_FOUND"
7596
- ]
7613
+ ],
7614
+ "x-cli": {
7615
+ "name": "list",
7616
+ "positional": [
7617
+ "handle"
7618
+ ]
7619
+ }
7597
7620
  },
7598
7621
  "post": {
7599
7622
  "operationId": "createOpsInvestigation",
7600
7623
  "summary": "Record an investigation",
7601
7624
  "description": "Append one structured investigation record to a queue item — the AI-write\nseam the cockpit's detail panel renders read-only. Post your findings\n(`kind: investigated`), a blocking question for the team (`kind:\nquestion`), or how to verify the fix (`kind: ready_for_qa` with\n`qaNotes`). Append-only and create-only, so it is safe for restricted ops\nkeys.\n\n**Use case:** After working an item, leave a findings write-up (summary,\nmarkdown findings, sources inspected, confidence) so the team — and the\nnext agent run — sees what you learned.",
7602
7625
  "tags": [
7603
- "Ops"
7626
+ "Investigations"
7604
7627
  ],
7605
7628
  "parameters": [
7606
7629
  {
@@ -7688,7 +7711,110 @@
7688
7711
  "FORBIDDEN",
7689
7712
  "NOT_FOUND",
7690
7713
  "VALIDATION"
7691
- ]
7714
+ ],
7715
+ "x-cli": {
7716
+ "name": "create",
7717
+ "positional": [
7718
+ "handle"
7719
+ ]
7720
+ }
7721
+ }
7722
+ },
7723
+ "/api/admin/ops/{handle}/investigation/{investigationId}": {
7724
+ "patch": {
7725
+ "operationId": "updateOpsInvestigation",
7726
+ "summary": "Update an investigation record",
7727
+ "description": "Update one existing investigation record in place — the write-back seam for\nthe `working` run record you were handed when a run was launched. Fill in\nthe `summary`/`findings`, attach the fixing PR, record your `confidence`\nand the `sources` you inspected, or flip its `kind` off `working` once the\ninvestigation is done. A partial patch: send only the fields you want to\nchange. Safe for restricted ops keys (it never reads or deletes).\n\n**Use case:** A run started with an empty `working` record; as you work,\nPATCH it with your findings so the cockpit's detail panel fills in live —\nno need to append a second record.",
7728
+ "tags": [
7729
+ "Investigations"
7730
+ ],
7731
+ "parameters": [
7732
+ {
7733
+ "$ref": "#/components/parameters/ProjectId"
7734
+ },
7735
+ {
7736
+ "name": "handle",
7737
+ "in": "path",
7738
+ "required": true,
7739
+ "description": "Per-project item number (e.g. `7`) or the full ops item id.",
7740
+ "schema": {
7741
+ "$ref": "#/components/schemas/ResourceId"
7742
+ }
7743
+ },
7744
+ {
7745
+ "name": "investigationId",
7746
+ "in": "path",
7747
+ "required": true,
7748
+ "description": "The investigation record id (from `POST`/`GET .../investigation` or the `runId` an ack/launch returned).",
7749
+ "schema": {
7750
+ "$ref": "#/components/schemas/ResourceId"
7751
+ }
7752
+ }
7753
+ ],
7754
+ "requestBody": {
7755
+ "required": true,
7756
+ "content": {
7757
+ "application/json": {
7758
+ "schema": {
7759
+ "$ref": "#/components/schemas/UpdateOpsInvestigationRequest"
7760
+ },
7761
+ "examples": {
7762
+ "findings": {
7763
+ "summary": "Fill in the run record's findings",
7764
+ "value": {
7765
+ "kind": "investigated",
7766
+ "summary": "Root cause is a stale KV read on the checkout flag.",
7767
+ "findings": "The `checkout.cta` gate is rebuilt without a CDN purge, so…",
7768
+ "confidence": "high",
7769
+ "prNumber": 4821,
7770
+ "prUrl": "https://github.com/acme/web/pull/4821"
7771
+ }
7772
+ }
7773
+ }
7774
+ }
7775
+ }
7776
+ },
7777
+ "responses": {
7778
+ "200": {
7779
+ "description": "The updated investigation record",
7780
+ "content": {
7781
+ "application/json": {
7782
+ "schema": {
7783
+ "$ref": "#/components/schemas/OpsInvestigation"
7784
+ }
7785
+ }
7786
+ }
7787
+ },
7788
+ "400": {
7789
+ "$ref": "#/components/responses/BadRequest"
7790
+ },
7791
+ "401": {
7792
+ "$ref": "#/components/responses/Unauthorized"
7793
+ },
7794
+ "403": {
7795
+ "$ref": "#/components/responses/Forbidden"
7796
+ },
7797
+ "404": {
7798
+ "$ref": "#/components/responses/NotFound"
7799
+ },
7800
+ "422": {
7801
+ "$ref": "#/components/responses/UnprocessableEntity"
7802
+ }
7803
+ },
7804
+ "x-error-codes": [
7805
+ "BAD_REQUEST",
7806
+ "UNAUTHORIZED",
7807
+ "FORBIDDEN",
7808
+ "NOT_FOUND",
7809
+ "VALIDATION"
7810
+ ],
7811
+ "x-cli": {
7812
+ "name": "update",
7813
+ "positional": [
7814
+ "handle",
7815
+ "investigationId"
7816
+ ]
7817
+ }
7692
7818
  }
7693
7819
  },
7694
7820
  "/api/admin/agent-profiles": {
@@ -12391,6 +12517,10 @@
12391
12517
  "locked": {
12392
12518
  "description": "If `true`, dashboard hides edit controls (e.g. the trailing public-floor entry).",
12393
12519
  "type": "boolean"
12520
+ },
12521
+ "whitelist": {
12522
+ "description": "Cosmetic marker. When `true`, the dashboard renders this condition as the pinned, always-first \"whitelist\" allowlist block (a direct `email`/`user_id` `in […]` list) rather than a numbered targeting step. Purely presentational — ignored by evaluation, which treats the entry as an ordinary condition.",
12523
+ "type": "boolean"
12394
12524
  }
12395
12525
  },
12396
12526
  "required": [
@@ -12926,6 +13056,10 @@
12926
13056
  "locked": {
12927
13057
  "description": "If `true`, dashboard hides edit controls (e.g. the trailing public-floor entry).",
12928
13058
  "type": "boolean"
13059
+ },
13060
+ "whitelist": {
13061
+ "description": "Cosmetic marker. When `true`, the dashboard renders this condition as the pinned, always-first \"whitelist\" allowlist block (a direct `email`/`user_id` `in […]` list) rather than a numbered targeting step. Purely presentational — ignored by evaluation, which treats the entry as an ordinary condition.",
13062
+ "type": "boolean"
12929
13063
  }
12930
13064
  },
12931
13065
  "required": [
@@ -13322,6 +13456,10 @@
13322
13456
  "locked": {
13323
13457
  "description": "If `true`, dashboard hides edit controls (e.g. the trailing public-floor entry).",
13324
13458
  "type": "boolean"
13459
+ },
13460
+ "whitelist": {
13461
+ "description": "Cosmetic marker. When `true`, the dashboard renders this condition as the pinned, always-first \"whitelist\" allowlist block (a direct `email`/`user_id` `in […]` list) rather than a numbered targeting step. Purely presentational — ignored by evaluation, which treats the entry as an ordinary condition.",
13462
+ "type": "boolean"
13325
13463
  }
13326
13464
  },
13327
13465
  "required": [
@@ -15588,7 +15726,24 @@
15588
15726
  "description": "JSON Schema (draft 2020-12) describing the shape of the config value. Top-level `type` must be `'object'`; every published value is validated against this schema."
15589
15727
  },
15590
15728
  "value": {
15729
+ "type": "object",
15730
+ "additionalProperties": {},
15591
15731
  "description": "Initial config value. Either a single JSON object applied to every env, or a `{ env: value }` map seeding per-env values. Must match `schema`. Defaults to `{}` on every env when omitted."
15732
+ },
15733
+ "dev": {
15734
+ "type": "object",
15735
+ "additionalProperties": {},
15736
+ "description": "Seed the **dev** env's initial value (version 1), overriding `value` for dev. Published immediately. Must match `schema`."
15737
+ },
15738
+ "staging": {
15739
+ "type": "object",
15740
+ "additionalProperties": {},
15741
+ "description": "Seed the **staging** env's initial value (version 1), overriding `value` for staging. Published immediately. Must match `schema`."
15742
+ },
15743
+ "prod": {
15744
+ "type": "object",
15745
+ "additionalProperties": {},
15746
+ "description": "Seed the **prod** env's initial value (version 1), overriding `value` for prod. Published immediately. Must match `schema`."
15592
15747
  }
15593
15748
  },
15594
15749
  "required": [
@@ -15596,7 +15751,7 @@
15596
15751
  "schema"
15597
15752
  ],
15598
15753
  "additionalProperties": false,
15599
- "description": "Body for `POST /api/admin/configs`. `name` + `schema` required."
15754
+ "description": "Body for `POST /api/admin/configs`. `name` + `schema` required. Per-env `dev`/`staging`/`prod` values are published to that env at version 1 (overriding `value`)."
15600
15755
  },
15601
15756
  "CreateConfigResponse": {
15602
15757
  "type": "object",
@@ -15784,14 +15939,31 @@
15784
15939
  "additionalProperties": {}
15785
15940
  },
15786
15941
  "value": {
15787
- "description": "Flat value applied to **every** env. Publishes a new version per env. To target one env, use `PUT /{id}/drafts` then `POST /{id}/publish`."
15942
+ "type": "object",
15943
+ "additionalProperties": {},
15944
+ "description": "Flat value applied to **every** env. Publishes a new version per env. To publish one env only, pass that env's key (`dev`/`staging`/`prod`) instead."
15945
+ },
15946
+ "dev": {
15947
+ "type": "object",
15948
+ "additionalProperties": {},
15949
+ "description": "Publish a new version to the **dev** env only, immediately (no draft). Overrides `value` for dev. Must match the effective schema."
15950
+ },
15951
+ "staging": {
15952
+ "type": "object",
15953
+ "additionalProperties": {},
15954
+ "description": "Publish a new version to the **staging** env only, immediately (no draft). Overrides `value` for staging. Must match the effective schema."
15955
+ },
15956
+ "prod": {
15957
+ "type": "object",
15958
+ "additionalProperties": {},
15959
+ "description": "Publish a new version to the **prod** env only, immediately (no draft). Overrides `value` for prod. Must match the effective schema."
15788
15960
  },
15789
15961
  "folder": {
15790
15962
  "$ref": "#/components/schemas/Folder"
15791
15963
  }
15792
15964
  },
15793
15965
  "additionalProperties": false,
15794
- "description": "Body for `PATCH /api/admin/configs/{id}`. Partial — only supplied fields change. `value` republishes on every env."
15966
+ "description": "Body for `PATCH /api/admin/configs/{id}`. Partial — only supplied fields change. `value` republishes on every env; per-env `dev`/`staging`/`prod` publish a new version to just that env."
15795
15967
  },
15796
15968
  "UpdateConfigResponse": {
15797
15969
  "type": "object",
@@ -15822,6 +15994,8 @@
15822
15994
  "$ref": "#/components/schemas/Env"
15823
15995
  },
15824
15996
  "value": {
15997
+ "type": "object",
15998
+ "additionalProperties": {},
15825
15999
  "description": "Draft value to stage on `env`. Validated against the config's current schema."
15826
16000
  }
15827
16001
  },
@@ -18135,6 +18309,17 @@
18135
18309
  ],
18136
18310
  "description": "Desired direction of movement. `higher_better` (default), `lower_better`, or `neutral` (guardrail)."
18137
18311
  },
18312
+ "MetricDisplayUnit": {
18313
+ "description": "Display unit (e.g. `ms`, `%`, `$`), or `null` when unitless.",
18314
+ "anyOf": [
18315
+ {
18316
+ "type": "string"
18317
+ },
18318
+ {
18319
+ "type": "null"
18320
+ }
18321
+ ]
18322
+ },
18138
18323
  "CreateMetricWithQuery": {
18139
18324
  "type": "object",
18140
18325
  "properties": {
@@ -18158,6 +18343,9 @@
18158
18343
  },
18159
18344
  "direction": {
18160
18345
  "$ref": "#/components/schemas/MetricDirection"
18346
+ },
18347
+ "unit": {
18348
+ "$ref": "#/components/schemas/MetricDisplayUnit"
18161
18349
  }
18162
18350
  },
18163
18351
  "required": [
@@ -18191,6 +18379,9 @@
18191
18379
  },
18192
18380
  "direction": {
18193
18381
  "$ref": "#/components/schemas/MetricDirection"
18382
+ },
18383
+ "unit": {
18384
+ "$ref": "#/components/schemas/MetricDisplayUnit"
18194
18385
  }
18195
18386
  },
18196
18387
  "required": [
@@ -18417,6 +18608,9 @@
18417
18608
  },
18418
18609
  "direction": {
18419
18610
  "$ref": "#/components/schemas/MetricDirection"
18611
+ },
18612
+ "unit": {
18613
+ "$ref": "#/components/schemas/MetricDisplayUnit"
18420
18614
  }
18421
18615
  },
18422
18616
  "required": [
@@ -18445,6 +18639,9 @@
18445
18639
  },
18446
18640
  "direction": {
18447
18641
  "$ref": "#/components/schemas/MetricDirection"
18642
+ },
18643
+ "unit": {
18644
+ "$ref": "#/components/schemas/MetricDisplayUnit"
18448
18645
  }
18449
18646
  },
18450
18647
  "required": [
@@ -18470,10 +18667,13 @@
18470
18667
  },
18471
18668
  "direction": {
18472
18669
  "$ref": "#/components/schemas/MetricDirection"
18670
+ },
18671
+ "unit": {
18672
+ "$ref": "#/components/schemas/MetricDisplayUnit"
18473
18673
  }
18474
18674
  },
18475
18675
  "additionalProperties": false,
18476
- "description": "Update-metric variant that leaves the query untouched (metadata-only edit — folder, event, winsorisation, default minimum effect of interest, direction)."
18676
+ "description": "Update-metric variant that leaves the query untouched (metadata-only edit — folder, event, winsorisation, default minimum effect of interest, direction, display unit)."
18477
18677
  },
18478
18678
  "UpdateMetricRequest": {
18479
18679
  "oneOf": [
@@ -19955,6 +20155,27 @@
19955
20155
  "additionalProperties": false,
19956
20156
  "description": "The fully-resolved owner of a queue item — a person and/or an AI agent. The two halves are independent: an item may have a person, an agent, both, or neither (both `null`)."
19957
20157
  },
20158
+ "OpsRunAction": {
20159
+ "type": "string",
20160
+ "enum": [
20161
+ "link_pr",
20162
+ "notify",
20163
+ "status",
20164
+ "superseded"
20165
+ ],
20166
+ "description": "The final action that closed a run record — `link_pr`/`notify` are the agent's terminal ops actions, `status` a completion status flip (ready_for_qa/resolved), `superseded` a newer ack replacing an open run."
20167
+ },
20168
+ "OpsRunActionOrNull": {
20169
+ "anyOf": [
20170
+ {
20171
+ "$ref": "#/components/schemas/OpsRunAction"
20172
+ },
20173
+ {
20174
+ "type": "null"
20175
+ }
20176
+ ],
20177
+ "description": "Which final action closed the run, or `null` while it is open (or a non-run record)."
20178
+ },
19958
20179
  "OpsRun": {
19959
20180
  "type": "object",
19960
20181
  "properties": {
@@ -20006,11 +20227,7 @@
20006
20227
  ],
20007
20228
  "description": "The agent-run session id recorded on the ack (dashboard deep-links to the run page), or `null`."
20008
20229
  },
20009
- "startedAt": {
20010
- "type": "string",
20011
- "description": "ISO-8601 timestamp the run started (the ack time)."
20012
- },
20013
- "completedAt": {
20230
+ "sessionUrl": {
20014
20231
  "anyOf": [
20015
20232
  {
20016
20233
  "type": "string"
@@ -20019,24 +20236,25 @@
20019
20236
  "type": "null"
20020
20237
  }
20021
20238
  ],
20022
- "description": "ISO-8601 timestamp the run closed, or `null` while still open."
20239
+ "description": "The run's session-page deep link, or `null`. DERIVED (never stored): rebuilt from `sessionId` + the run's trigger connector — Claude's routine id (`?trigger=`), Copilot's repo (`/tasks/`), Cursor/Jules from the id alone."
20023
20240
  },
20024
- "completedAction": {
20241
+ "startedAt": {
20242
+ "type": "string",
20243
+ "description": "ISO-8601 timestamp the run started (the ack time)."
20244
+ },
20245
+ "completedAt": {
20025
20246
  "anyOf": [
20026
20247
  {
20027
- "type": "string",
20028
- "enum": [
20029
- "link_pr",
20030
- "notify",
20031
- "status",
20032
- "superseded"
20033
- ]
20248
+ "type": "string"
20034
20249
  },
20035
20250
  {
20036
20251
  "type": "null"
20037
20252
  }
20038
20253
  ],
20039
- "description": "Which final action closed the run — `link_pr`/`notify` are the agent's terminal ops actions, `status` a completion status flip (ready_for_qa/resolved), `superseded` a newer ack replacing it. `null` while the run is open."
20254
+ "description": "ISO-8601 timestamp the run closed, or `null` while still open."
20255
+ },
20256
+ "completedAction": {
20257
+ "$ref": "#/components/schemas/OpsRunActionOrNull"
20040
20258
  },
20041
20259
  "prNumber": {
20042
20260
  "anyOf": [
@@ -20067,6 +20285,7 @@
20067
20285
  "connectorId",
20068
20286
  "ackedBy",
20069
20287
  "sessionId",
20288
+ "sessionUrl",
20070
20289
  "startedAt",
20071
20290
  "completedAt",
20072
20291
  "completedAction",
@@ -20351,6 +20570,42 @@
20351
20570
  ],
20352
20571
  "description": "Initial triage priority, or `null`."
20353
20572
  },
20573
+ "status": {
20574
+ "anyOf": [
20575
+ {
20576
+ "$ref": "#/components/schemas/OpsItemStatus"
20577
+ }
20578
+ ],
20579
+ "description": "Initial lifecycle status; defaults to `open` when omitted."
20580
+ },
20581
+ "assigneeId": {
20582
+ "anyOf": [
20583
+ {
20584
+ "type": "string"
20585
+ },
20586
+ {
20587
+ "type": "null"
20588
+ }
20589
+ ],
20590
+ "description": "The `users.id` of the person to assign as owner at creation, or `null`."
20591
+ },
20592
+ "subscribers": {
20593
+ "type": "array",
20594
+ "items": {
20595
+ "type": "string",
20596
+ "format": "email"
20597
+ },
20598
+ "default": [],
20599
+ "description": "Emails of teammates to subscribe to this item's Slack pings at creation."
20600
+ },
20601
+ "tags": {
20602
+ "type": "array",
20603
+ "items": {
20604
+ "type": "string"
20605
+ },
20606
+ "default": [],
20607
+ "description": "Tag names to attach at creation (get-or-created by name, deduped case-insensitively)."
20608
+ },
20354
20609
  "reporterEmail": {
20355
20610
  "anyOf": [
20356
20611
  {
@@ -20470,6 +20725,42 @@
20470
20725
  ],
20471
20726
  "description": "Initial triage priority, or `null`."
20472
20727
  },
20728
+ "status": {
20729
+ "anyOf": [
20730
+ {
20731
+ "$ref": "#/components/schemas/OpsItemStatus"
20732
+ }
20733
+ ],
20734
+ "description": "Initial lifecycle status; defaults to `open` when omitted."
20735
+ },
20736
+ "assigneeId": {
20737
+ "anyOf": [
20738
+ {
20739
+ "type": "string"
20740
+ },
20741
+ {
20742
+ "type": "null"
20743
+ }
20744
+ ],
20745
+ "description": "The `users.id` of the person to assign as owner at creation, or `null`."
20746
+ },
20747
+ "subscribers": {
20748
+ "type": "array",
20749
+ "items": {
20750
+ "type": "string",
20751
+ "format": "email"
20752
+ },
20753
+ "default": [],
20754
+ "description": "Emails of teammates to subscribe to this item's Slack pings at creation."
20755
+ },
20756
+ "tags": {
20757
+ "type": "array",
20758
+ "items": {
20759
+ "type": "string"
20760
+ },
20761
+ "default": [],
20762
+ "description": "Tag names to attach at creation (get-or-created by name, deduped case-insensitively)."
20763
+ },
20473
20764
  "reporterEmail": {
20474
20765
  "anyOf": [
20475
20766
  {
@@ -21431,7 +21722,7 @@
21431
21722
  ],
21432
21723
  "description": "The agent-run session id, or `null`."
21433
21724
  },
21434
- "ackedBy": {
21725
+ "sessionUrl": {
21435
21726
  "anyOf": [
21436
21727
  {
21437
21728
  "type": "string"
@@ -21440,24 +21731,21 @@
21440
21731
  "type": "null"
21441
21732
  }
21442
21733
  ],
21443
- "description": "Email of the human who acked (run records for a human ack), or `null`."
21734
+ "description": "The run's session-page deep link, or `null`. DERIVED (never stored): rebuilt from `sessionId` + the run's trigger connector — Claude's routine id (`?trigger=`), Copilot's repo (`/tasks/`), Cursor/Jules from the id alone. Only `working` run records carry one."
21444
21735
  },
21445
- "completedAction": {
21736
+ "ackedBy": {
21446
21737
  "anyOf": [
21447
21738
  {
21448
- "type": "string",
21449
- "enum": [
21450
- "link_pr",
21451
- "notify",
21452
- "status",
21453
- "superseded"
21454
- ]
21739
+ "type": "string"
21455
21740
  },
21456
21741
  {
21457
21742
  "type": "null"
21458
21743
  }
21459
21744
  ],
21460
- "description": "Which final action closed a `working` run record, or `null` (open run / non-run record)."
21745
+ "description": "Email of the human who acked (run records for a human ack), or `null`."
21746
+ },
21747
+ "completedAction": {
21748
+ "$ref": "#/components/schemas/OpsRunActionOrNull"
21461
21749
  },
21462
21750
  "createdAt": {
21463
21751
  "type": "string",
@@ -21489,6 +21777,7 @@
21489
21777
  "startedAt",
21490
21778
  "completedAt",
21491
21779
  "sessionId",
21780
+ "sessionUrl",
21492
21781
  "ackedBy",
21493
21782
  "completedAction",
21494
21783
  "createdAt",
@@ -21639,6 +21928,119 @@
21639
21928
  "additionalProperties": false,
21640
21929
  "description": "Body for `POST /api/admin/ops/{handle}/investigation`. `kind` is required; include at least one content field (`summary`/`findings`/`question`/`qaNotes`) — the panel renders whatever it gets."
21641
21930
  },
21931
+ "UpdateOpsInvestigationRequest": {
21932
+ "type": "object",
21933
+ "properties": {
21934
+ "kind": {
21935
+ "type": "string",
21936
+ "enum": [
21937
+ "investigated",
21938
+ "detected",
21939
+ "question",
21940
+ "ready_for_qa",
21941
+ "working",
21942
+ "note"
21943
+ ],
21944
+ "description": "Reclassify the record's lifecycle stage (e.g. flip a `working` run into `investigated` once findings land)."
21945
+ },
21946
+ "summary": {
21947
+ "type": "string",
21948
+ "maxLength": 2000,
21949
+ "description": "One-line summary of the record."
21950
+ },
21951
+ "findings": {
21952
+ "type": "string",
21953
+ "maxLength": 50000,
21954
+ "description": "The full findings write-up (markdown)."
21955
+ },
21956
+ "question": {
21957
+ "type": "string",
21958
+ "maxLength": 10000,
21959
+ "description": "A blocking question for the team (markdown)."
21960
+ },
21961
+ "qaNotes": {
21962
+ "type": "string",
21963
+ "maxLength": 50000,
21964
+ "description": "How to verify the fix — QA notes (markdown)."
21965
+ },
21966
+ "model": {
21967
+ "type": "string",
21968
+ "maxLength": 200,
21969
+ "description": "The model the agent ran on."
21970
+ },
21971
+ "prNumber": {
21972
+ "type": "integer",
21973
+ "description": "A PR the record references."
21974
+ },
21975
+ "prUrl": {
21976
+ "type": "string",
21977
+ "format": "uri",
21978
+ "maxLength": 2000,
21979
+ "description": "HTML URL of that PR."
21980
+ },
21981
+ "sources": {
21982
+ "type": "array",
21983
+ "maxItems": 200,
21984
+ "items": {
21985
+ "type": "object",
21986
+ "properties": {
21987
+ "path": {
21988
+ "type": "string",
21989
+ "description": "Repo-relative file path inspected."
21990
+ },
21991
+ "url": {
21992
+ "type": "string",
21993
+ "description": "External link consulted."
21994
+ },
21995
+ "label": {
21996
+ "type": "string",
21997
+ "description": "Human-readable label for the source."
21998
+ }
21999
+ },
22000
+ "additionalProperties": false,
22001
+ "description": "One file/link inspected while producing the record."
22002
+ },
22003
+ "description": "The files/links inspected."
22004
+ },
22005
+ "confidence": {
22006
+ "type": "string",
22007
+ "enum": [
22008
+ "low",
22009
+ "medium",
22010
+ "high"
22011
+ ],
22012
+ "description": "Self-reported confidence in the record."
22013
+ },
22014
+ "tokensUsed": {
22015
+ "type": "integer",
22016
+ "description": "Tokens the run consumed."
22017
+ },
22018
+ "durationMs": {
22019
+ "type": "integer",
22020
+ "description": "Run duration in milliseconds."
22021
+ },
22022
+ "visibility": {
22023
+ "type": "string",
22024
+ "enum": [
22025
+ "draft",
22026
+ "published"
22027
+ ],
22028
+ "description": "Record visibility. `draft` keeps it out of the panel; `published` surfaces it."
22029
+ },
22030
+ "completedAt": {
22031
+ "type": "string",
22032
+ "description": "ISO-8601 timestamp the work finished. Set it (or flip `kind` off `working`) to mark a run record done."
22033
+ },
22034
+ "sessionId": {
22035
+ "type": "string",
22036
+ "maxLength": 300,
22037
+ "description": "The agent-run session id, so the dashboard can deep-link to the run."
22038
+ }
22039
+ },
22040
+ "additionalProperties": false,
22041
+ "minProperties": 1,
22042
+ "description": "Body for `PATCH /api/admin/ops/{handle}/investigation/{investigationId}` — a partial update of one existing investigation record (typically the `working` run record you were handed). Send only the fields you want to change; at least one is required."
22043
+ },
21642
22044
  "OpsAgentProfile": {
21643
22045
  "type": "object",
21644
22046
  "properties": {