@oneharness/sdk 0.11.3 → 0.12.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.
@@ -57,7 +57,7 @@ export type ControlVerb = "interrupt";
57
57
  * new variant is a report `schema_version` bump like any other enum value, since
58
58
  * a consumer matching exhaustively learns of it only from the version.
59
59
  */
60
- export type FallThroughReason = "not-installed" | "spawn-error" | "auth" | "quota" | "session-not-found" | "untrusted-directory" | "input-too-large" | "model-not-found" | "rate-limit";
60
+ export type FallThroughReason = "not-installed" | "spawn-error" | "auth" | "quota" | "session-not-found" | "untrusted-directory" | "input-too-large" | "model-mismatch" | "model-not-found" | "rate-limit";
61
61
  export type ToolCallStatus = "completed" | "failed" | "timeout" | "interrupted";
62
62
  /**
63
63
  * How a normalized tool interval was obtained.
@@ -74,7 +74,7 @@ export type TimingSource = "provider_measured" | "stdout_observed";
74
74
  * the report, history) one definition to share instead of scattered string
75
75
  * literals.
76
76
  */
77
- export type FailureKind = "auth" | "rate_limit" | "model_not_found" | "quota" | "session_not_found" | "tool_deferred" | "untrusted_directory" | "input_too_large";
77
+ export type FailureKind = "auth" | "rate_limit" | "model_not_found" | "quota" | "session_not_found" | "tool_deferred" | "untrusted_directory" | "input_too_large" | "model_mismatch";
78
78
  /**
79
79
  * How a harness emits its result, which decides how `text` is extracted.
80
80
  *
@@ -308,7 +308,8 @@ export interface FallbackReport {
308
308
  * The candidates fallen through because they could not run the task at all,
309
309
  * in priority order, each with why (`not-installed`, `spawn-error`, `auth`,
310
310
  * `quota`, `session-not-found`, `untrusted-directory`, `input-too-large`,
311
- * and — on a model fan-out — `model-not-found` / `rate-limit`; see
311
+ * `model-mismatch`, and — on a model fan-out — `model-not-found` /
312
+ * `rate-limit`; see
312
313
  * [`crate::domain::fallback::startup_failure_reason`]).
313
314
  */
314
315
  fell_through: FallThrough[];
@@ -415,7 +416,8 @@ export interface RunResult {
415
416
  * Best-effort failure reason; `null` when unclassified. Distinct from
416
417
  * `status`, which records oneharness's relationship to the process. Two
417
418
  * families: coarse reasons for a non-zero run (`auth`, `rate_limit`,
418
- * `model_not_found`, `quota`, `session_not_found`), and `tool_deferred` — a run that exited
419
+ * `model_not_found`, `quota`, `session_not_found`, `untrusted_directory`,
420
+ * `input_too_large`, `model_mismatch`), and `tool_deferred` — a run that exited
419
421
  * *cleanly* but only deferred a builtin tool call instead of executing it
420
422
  * (Claude Code bridge/managed deployments), so it did no useful work. The
421
423
  * deferred case is the only `failure_kind` that can appear on a `status: ok`
@@ -445,6 +447,17 @@ export interface RunResult {
445
447
  * without parsing the argv.
446
448
  */
447
449
  model: string | null;
450
+ /**
451
+ * The model the harness **itself** reported the conversation would run
452
+ * under, read off its own protocol before any token was spent — for codex
453
+ * over `app-server`, `result.model` of the `thread/start` / `thread/resume`
454
+ * response. `null` on every path that reports none, which today is every
455
+ * path but codex's app-server. Never inferred and never copied from
456
+ * `model`: where both are set they are the requested model and the served
457
+ * one, and a difference between them is exactly the `model_mismatch`
458
+ * refusal, which this field then names the other half of.
459
+ */
460
+ observed_model: string | null;
448
461
  output_format: OutputFormat;
449
462
  /**
450
463
  * The prompt this result ran, set only on a **batch** run (one harness
@@ -6,7 +6,7 @@ export type HistoryLine = ({
6
6
  harness: string;
7
7
  harness_id?: string | null | undefined;
8
8
  run_id: string;
9
- schema_version: "1.2" | "1.3" | "1.4" | "1.5" | "1.6" | "1.7";
9
+ schema_version: "1.2" | "1.3" | "1.4" | "1.5" | "1.6" | "1.7" | "1.8";
10
10
  type: "event";
11
11
  variant?: string | null | undefined;
12
12
  [k: string]: unknown;
@@ -27,7 +27,7 @@ export type HistoryLine = ({
27
27
  [k: string]: unknown;
28
28
  } | ({
29
29
  error: string;
30
- schema_version?: "1.3" | "1.4" | "1.5" | "1.6" | "1.7" | undefined;
30
+ schema_version?: "1.3" | "1.4" | "1.5" | "1.6" | "1.7" | "1.8" | undefined;
31
31
  [k: string]: unknown;
32
32
  } & ({
33
33
  status?: "nonzero" | "timeout" | "cancelled" | "spawn-error" | "skipped" | undefined;
@@ -39,27 +39,40 @@ export type HistoryLine = ({
39
39
  work?: null | undefined;
40
40
  [k: string]: unknown;
41
41
  } | {
42
- schema_version?: "1.7" | undefined;
42
+ schema_version?: "1.7" | "1.8" | undefined;
43
43
  status?: "nonzero" | "timeout" | "cancelled" | undefined;
44
44
  work: "done" | "none";
45
45
  [k: string]: unknown;
46
+ }) & ({
47
+ observed_model?: null | undefined;
48
+ [k: string]: unknown;
49
+ } | {
50
+ observed_model: string;
51
+ schema_version?: "1.8" | undefined;
52
+ [k: string]: unknown;
46
53
  }) & ({
47
54
  status?: "ok" | "nonzero" | "timeout" | "spawn-error" | "skipped" | "planned" | undefined;
48
55
  [k: string]: unknown;
49
56
  } | {
50
- schema_version?: "1.4" | "1.5" | "1.6" | "1.7" | undefined;
57
+ schema_version?: "1.4" | "1.5" | "1.6" | "1.7" | "1.8" | undefined;
51
58
  [k: string]: unknown;
52
59
  }) & (({
53
- failure_kind?: "auth" | "rate_limit" | "model_not_found" | "quota" | "tool_deferred" | "untrusted_directory" | "input_too_large" | null;
60
+ failure_kind?: "auth" | "rate_limit" | "model_not_found" | "quota" | "tool_deferred" | "untrusted_directory" | "input_too_large" | "model_mismatch" | null;
61
+ [k: string]: unknown;
62
+ } | {
63
+ schema_version?: "1.5" | "1.6" | "1.7" | "1.8" | undefined;
64
+ [k: string]: unknown;
65
+ }) & ({
66
+ failure_kind?: "auth" | "rate_limit" | "model_not_found" | "quota" | "session_not_found" | "tool_deferred" | "model_mismatch" | null;
54
67
  [k: string]: unknown;
55
68
  } | {
56
- schema_version?: "1.5" | "1.6" | "1.7" | undefined;
69
+ schema_version?: "1.6" | "1.7" | "1.8" | undefined;
57
70
  [k: string]: unknown;
58
71
  }) & ({
59
- failure_kind?: "auth" | "rate_limit" | "model_not_found" | "quota" | "session_not_found" | "tool_deferred" | null;
72
+ failure_kind?: "auth" | "rate_limit" | "model_not_found" | "quota" | "session_not_found" | "tool_deferred" | "untrusted_directory" | "input_too_large" | null;
60
73
  [k: string]: unknown;
61
74
  } | {
62
- schema_version?: "1.6" | "1.7" | undefined;
75
+ schema_version?: "1.8" | undefined;
63
76
  [k: string]: unknown;
64
77
  })) & ({
65
78
  duration_ms: number;
@@ -78,11 +91,16 @@ export type HistoryLine = ({
78
91
  model: string | null;
79
92
  model_ms: number;
80
93
  name: string;
94
+ /**
95
+ * The model the harness itself reported it would run under (see
96
+ * [`HistoryRecord::observed_model`]). Omitted on the wire when absent.
97
+ */
98
+ observed_model?: string | null | undefined;
81
99
  observed_tool_ms?: never | undefined;
82
100
  permission_mode: PermissionMode;
83
101
  project: string;
84
102
  prompt: string;
85
- schema_version: "1.0" | "1.1" | "1.2" | "1.3" | "1.4" | "1.5" | "1.6" | "1.7";
103
+ schema_version: "1.0" | "1.1" | "1.2" | "1.3" | "1.4" | "1.5" | "1.6" | "1.7" | "1.8";
86
104
  session: string;
87
105
  session_id: string | null;
88
106
  started_at: string;
@@ -118,11 +136,16 @@ export type HistoryLine = ({
118
136
  model: string | null;
119
137
  model_ms: number;
120
138
  name: string;
139
+ /**
140
+ * The model the harness itself reported it would run under (see
141
+ * [`HistoryRecord::observed_model`]). Omitted on the wire when absent.
142
+ */
143
+ observed_model?: string | null | undefined;
121
144
  observed_tool_ms?: never | undefined;
122
145
  permission_mode: PermissionMode;
123
146
  project: string;
124
147
  prompt: string;
125
- schema_version: "1.0" | "1.1" | "1.2" | "1.3" | "1.4" | "1.5" | "1.6" | "1.7";
148
+ schema_version: "1.0" | "1.1" | "1.2" | "1.3" | "1.4" | "1.5" | "1.6" | "1.7" | "1.8";
126
149
  session: string;
127
150
  session_id: string | null;
128
151
  started_at: string;
@@ -158,11 +181,16 @@ export type HistoryLine = ({
158
181
  model: string | null;
159
182
  model_ms?: never | undefined;
160
183
  name: string;
184
+ /**
185
+ * The model the harness itself reported it would run under (see
186
+ * [`HistoryRecord::observed_model`]). Omitted on the wire when absent.
187
+ */
188
+ observed_model?: string | null | undefined;
161
189
  observed_tool_ms: number;
162
190
  permission_mode: PermissionMode;
163
191
  project: string;
164
192
  prompt: string;
165
- schema_version: "1.2" | "1.3" | "1.4" | "1.5" | "1.6" | "1.7";
193
+ schema_version: "1.2" | "1.3" | "1.4" | "1.5" | "1.6" | "1.7" | "1.8";
166
194
  session: string;
167
195
  session_id: string | null;
168
196
  started_at?: never | undefined;
@@ -198,11 +226,16 @@ export type HistoryLine = ({
198
226
  model: string | null;
199
227
  model_ms?: never | undefined;
200
228
  name: string;
229
+ /**
230
+ * The model the harness itself reported it would run under (see
231
+ * [`HistoryRecord::observed_model`]). Omitted on the wire when absent.
232
+ */
233
+ observed_model?: string | null | undefined;
201
234
  observed_tool_ms?: never | undefined;
202
235
  permission_mode: PermissionMode;
203
236
  project: string;
204
237
  prompt: string;
205
- schema_version: "1.0" | "1.1" | "1.2" | "1.3" | "1.4" | "1.5" | "1.6" | "1.7";
238
+ schema_version: "1.0" | "1.1" | "1.2" | "1.3" | "1.4" | "1.5" | "1.6" | "1.7" | "1.8";
206
239
  session: string;
207
240
  session_id: string | null;
208
241
  started_at?: never | undefined;
@@ -238,11 +271,16 @@ export type HistoryLine = ({
238
271
  model: string | null;
239
272
  model_ms?: never | undefined;
240
273
  name: string;
274
+ /**
275
+ * The model the harness itself reported it would run under (see
276
+ * [`HistoryRecord::observed_model`]). Omitted on the wire when absent.
277
+ */
278
+ observed_model?: string | null | undefined;
241
279
  observed_tool_ms?: never | undefined;
242
280
  permission_mode: PermissionMode;
243
281
  project: string;
244
282
  prompt: string;
245
- schema_version: "1.3" | "1.4" | "1.5" | "1.6" | "1.7";
283
+ schema_version: "1.3" | "1.4" | "1.5" | "1.6" | "1.7" | "1.8";
246
284
  session: string;
247
285
  session_id: string | null;
248
286
  started_at: string;
@@ -278,11 +316,16 @@ export type HistoryLine = ({
278
316
  model: string | null;
279
317
  model_ms?: never | undefined;
280
318
  name: string;
319
+ /**
320
+ * The model the harness itself reported it would run under (see
321
+ * [`HistoryRecord::observed_model`]). Omitted on the wire when absent.
322
+ */
323
+ observed_model?: string | null | undefined;
281
324
  observed_tool_ms?: never | undefined;
282
325
  permission_mode: PermissionMode;
283
326
  project: string;
284
327
  prompt: string;
285
- schema_version: "1.0" | "1.1" | "1.2" | "1.3" | "1.4" | "1.5" | "1.6" | "1.7";
328
+ schema_version: "1.0" | "1.1" | "1.2" | "1.3" | "1.4" | "1.5" | "1.6" | "1.7" | "1.8";
286
329
  session: string;
287
330
  session_id: string | null;
288
331
  started_at?: never | undefined;
@@ -318,7 +361,7 @@ export type TimingSource = "provider_measured" | "stdout_observed";
318
361
  * the report, history) one definition to share instead of scattered string
319
362
  * literals.
320
363
  */
321
- export type FailureKind = "auth" | "rate_limit" | "model_not_found" | "quota" | "session_not_found" | "tool_deferred" | "untrusted_directory" | "input_too_large";
364
+ export type FailureKind = "auth" | "rate_limit" | "model_not_found" | "quota" | "session_not_found" | "tool_deferred" | "untrusted_directory" | "input_too_large" | "model_mismatch";
322
365
  /**
323
366
  * The unified approval mode, from least to most autonomy. A harness may not
324
367
  * support every value (see [`crate::domain::harness::HarnessSpec::mode`]); the
@@ -69,7 +69,10 @@ export type HistoryRecord = {
69
69
  history_id: string;
70
70
  labels?: HistoryLabels | undefined;
71
71
  /**
72
- * The effective top-level model for the run, if any.
72
+ * The model this run **requested** — the value oneharness put on the
73
+ * harness's model flag or protocol frame — if any. Copied from
74
+ * [`RunResult::model`], so it keeps meaning the requested model even where
75
+ * `observed_model` below is present.
73
76
  */
74
77
  model: string | null;
75
78
  model_ms: number;
@@ -78,6 +81,22 @@ export type HistoryRecord = {
78
81
  * every record so a reader can resolve a session by name from any line.
79
82
  */
80
83
  name: string;
84
+ /**
85
+ * The model the harness **itself** reported the conversation would run
86
+ * under, read off its own protocol before any token was spent — for codex
87
+ * over `app-server`, `result.model` of the `thread/start` /
88
+ * `thread/resume` response. Copied from [`RunResult::observed_model`]:
89
+ * never inferred and never copied from `model`, and omitted on the wire on
90
+ * every path that reports none.
91
+ *
92
+ * On a completed app-server turn the two agree, because a turn whose
93
+ * reported model differed from the requested one was refused before it
94
+ * ran (`model_mismatch`) — so a completed record's `model` is what codex
95
+ * ran, and the record can no longer say one model while another was
96
+ * billed. They differ only on such a refused record, and where no model
97
+ * was requested at all. Gated to [`FIRST_MODEL_OBSERVATION_SCHEMA_VERSION`].
98
+ */
99
+ observed_model?: string | null | undefined;
81
100
  observed_tool_ms?: never | undefined;
82
101
  /**
83
102
  * The normalized approval mode requested for the run.
@@ -93,7 +112,7 @@ export type HistoryRecord = {
93
112
  * run's single prompt).
94
113
  */
95
114
  prompt: string;
96
- schema_version: "1.2" | "1.3" | "1.4" | "1.5" | "1.6" | "1.7";
115
+ schema_version: "1.2" | "1.3" | "1.4" | "1.5" | "1.6" | "1.7" | "1.8";
97
116
  /**
98
117
  * The oneharness session id this run belongs to (the history file's stem).
99
118
  */
@@ -211,7 +230,10 @@ export type HistoryRecord = {
211
230
  history_id: string;
212
231
  labels?: HistoryLabels1 | undefined;
213
232
  /**
214
- * The effective top-level model for the run, if any.
233
+ * The model this run **requested** — the value oneharness put on the
234
+ * harness's model flag or protocol frame — if any. Copied from
235
+ * [`RunResult::model`], so it keeps meaning the requested model even where
236
+ * `observed_model` below is present.
215
237
  */
216
238
  model: string | null;
217
239
  model_ms: number;
@@ -220,6 +242,22 @@ export type HistoryRecord = {
220
242
  * every record so a reader can resolve a session by name from any line.
221
243
  */
222
244
  name: string;
245
+ /**
246
+ * The model the harness **itself** reported the conversation would run
247
+ * under, read off its own protocol before any token was spent — for codex
248
+ * over `app-server`, `result.model` of the `thread/start` /
249
+ * `thread/resume` response. Copied from [`RunResult::observed_model`]:
250
+ * never inferred and never copied from `model`, and omitted on the wire on
251
+ * every path that reports none.
252
+ *
253
+ * On a completed app-server turn the two agree, because a turn whose
254
+ * reported model differed from the requested one was refused before it
255
+ * ran (`model_mismatch`) — so a completed record's `model` is what codex
256
+ * ran, and the record can no longer say one model while another was
257
+ * billed. They differ only on such a refused record, and where no model
258
+ * was requested at all. Gated to [`FIRST_MODEL_OBSERVATION_SCHEMA_VERSION`].
259
+ */
260
+ observed_model?: string | null | undefined;
223
261
  observed_tool_ms?: never | undefined;
224
262
  /**
225
263
  * The normalized approval mode requested for the run.
@@ -331,7 +369,10 @@ export type HistoryRecord = {
331
369
  history_id: string;
332
370
  labels?: HistoryLabels2 | undefined;
333
371
  /**
334
- * The effective top-level model for the run, if any.
372
+ * The model this run **requested** — the value oneharness put on the
373
+ * harness's model flag or protocol frame — if any. Copied from
374
+ * [`RunResult::model`], so it keeps meaning the requested model even where
375
+ * `observed_model` below is present.
335
376
  */
336
377
  model: string | null;
337
378
  model_ms?: never | undefined;
@@ -340,6 +381,22 @@ export type HistoryRecord = {
340
381
  * every record so a reader can resolve a session by name from any line.
341
382
  */
342
383
  name: string;
384
+ /**
385
+ * The model the harness **itself** reported the conversation would run
386
+ * under, read off its own protocol before any token was spent — for codex
387
+ * over `app-server`, `result.model` of the `thread/start` /
388
+ * `thread/resume` response. Copied from [`RunResult::observed_model`]:
389
+ * never inferred and never copied from `model`, and omitted on the wire on
390
+ * every path that reports none.
391
+ *
392
+ * On a completed app-server turn the two agree, because a turn whose
393
+ * reported model differed from the requested one was refused before it
394
+ * ran (`model_mismatch`) — so a completed record's `model` is what codex
395
+ * ran, and the record can no longer say one model while another was
396
+ * billed. They differ only on such a refused record, and where no model
397
+ * was requested at all. Gated to [`FIRST_MODEL_OBSERVATION_SCHEMA_VERSION`].
398
+ */
399
+ observed_model?: string | null | undefined;
343
400
  observed_tool_ms?: never | undefined;
344
401
  /**
345
402
  * The normalized approval mode requested for the run.
@@ -355,7 +412,7 @@ export type HistoryRecord = {
355
412
  * run's single prompt).
356
413
  */
357
414
  prompt: string;
358
- schema_version: "1.2" | "1.3" | "1.4" | "1.5" | "1.6" | "1.7";
415
+ schema_version: "1.2" | "1.3" | "1.4" | "1.5" | "1.6" | "1.7" | "1.8";
359
416
  /**
360
417
  * The oneharness session id this run belongs to (the history file's stem).
361
418
  */
@@ -439,7 +496,10 @@ export type HistoryRecord = {
439
496
  history_id: string;
440
497
  labels?: HistoryLabels3 | undefined;
441
498
  /**
442
- * The effective top-level model for the run, if any.
499
+ * The model this run **requested** — the value oneharness put on the
500
+ * harness's model flag or protocol frame — if any. Copied from
501
+ * [`RunResult::model`], so it keeps meaning the requested model even where
502
+ * `observed_model` below is present.
443
503
  */
444
504
  model: string | null;
445
505
  model_ms?: never | undefined;
@@ -448,6 +508,22 @@ export type HistoryRecord = {
448
508
  * every record so a reader can resolve a session by name from any line.
449
509
  */
450
510
  name: string;
511
+ /**
512
+ * The model the harness **itself** reported the conversation would run
513
+ * under, read off its own protocol before any token was spent — for codex
514
+ * over `app-server`, `result.model` of the `thread/start` /
515
+ * `thread/resume` response. Copied from [`RunResult::observed_model`]:
516
+ * never inferred and never copied from `model`, and omitted on the wire on
517
+ * every path that reports none.
518
+ *
519
+ * On a completed app-server turn the two agree, because a turn whose
520
+ * reported model differed from the requested one was refused before it
521
+ * ran (`model_mismatch`) — so a completed record's `model` is what codex
522
+ * ran, and the record can no longer say one model while another was
523
+ * billed. They differ only on such a refused record, and where no model
524
+ * was requested at all. Gated to [`FIRST_MODEL_OBSERVATION_SCHEMA_VERSION`].
525
+ */
526
+ observed_model?: string | null | undefined;
451
527
  observed_tool_ms: number;
452
528
  /**
453
529
  * The normalized approval mode requested for the run.
@@ -463,7 +539,7 @@ export type HistoryRecord = {
463
539
  * run's single prompt).
464
540
  */
465
541
  prompt: string;
466
- schema_version: "1.2" | "1.3" | "1.4" | "1.5" | "1.6" | "1.7";
542
+ schema_version: "1.2" | "1.3" | "1.4" | "1.5" | "1.6" | "1.7" | "1.8";
467
543
  /**
468
544
  * The oneharness session id this run belongs to (the history file's stem).
469
545
  */
@@ -547,7 +623,10 @@ export type HistoryRecord = {
547
623
  history_id: string;
548
624
  labels?: HistoryLabels4 | undefined;
549
625
  /**
550
- * The effective top-level model for the run, if any.
626
+ * The model this run **requested** — the value oneharness put on the
627
+ * harness's model flag or protocol frame — if any. Copied from
628
+ * [`RunResult::model`], so it keeps meaning the requested model even where
629
+ * `observed_model` below is present.
551
630
  */
552
631
  model: string | null;
553
632
  model_ms?: never | undefined;
@@ -556,6 +635,22 @@ export type HistoryRecord = {
556
635
  * every record so a reader can resolve a session by name from any line.
557
636
  */
558
637
  name: string;
638
+ /**
639
+ * The model the harness **itself** reported the conversation would run
640
+ * under, read off its own protocol before any token was spent — for codex
641
+ * over `app-server`, `result.model` of the `thread/start` /
642
+ * `thread/resume` response. Copied from [`RunResult::observed_model`]:
643
+ * never inferred and never copied from `model`, and omitted on the wire on
644
+ * every path that reports none.
645
+ *
646
+ * On a completed app-server turn the two agree, because a turn whose
647
+ * reported model differed from the requested one was refused before it
648
+ * ran (`model_mismatch`) — so a completed record's `model` is what codex
649
+ * ran, and the record can no longer say one model while another was
650
+ * billed. They differ only on such a refused record, and where no model
651
+ * was requested at all. Gated to [`FIRST_MODEL_OBSERVATION_SCHEMA_VERSION`].
652
+ */
653
+ observed_model?: string | null | undefined;
559
654
  observed_tool_ms?: never | undefined;
560
655
  /**
561
656
  * The normalized approval mode requested for the run.
@@ -571,7 +666,7 @@ export type HistoryRecord = {
571
666
  * run's single prompt).
572
667
  */
573
668
  prompt: string;
574
- schema_version: "1.2" | "1.3" | "1.4" | "1.5" | "1.6" | "1.7";
669
+ schema_version: "1.2" | "1.3" | "1.4" | "1.5" | "1.6" | "1.7" | "1.8";
575
670
  /**
576
671
  * The oneharness session id this run belongs to (the history file's stem).
577
672
  */
@@ -655,7 +750,10 @@ export type HistoryRecord = {
655
750
  history_id: string;
656
751
  labels?: HistoryLabels5 | undefined;
657
752
  /**
658
- * The effective top-level model for the run, if any.
753
+ * The model this run **requested** — the value oneharness put on the
754
+ * harness's model flag or protocol frame — if any. Copied from
755
+ * [`RunResult::model`], so it keeps meaning the requested model even where
756
+ * `observed_model` below is present.
659
757
  */
660
758
  model: string | null;
661
759
  model_ms?: never | undefined;
@@ -664,6 +762,22 @@ export type HistoryRecord = {
664
762
  * every record so a reader can resolve a session by name from any line.
665
763
  */
666
764
  name: string;
765
+ /**
766
+ * The model the harness **itself** reported the conversation would run
767
+ * under, read off its own protocol before any token was spent — for codex
768
+ * over `app-server`, `result.model` of the `thread/start` /
769
+ * `thread/resume` response. Copied from [`RunResult::observed_model`]:
770
+ * never inferred and never copied from `model`, and omitted on the wire on
771
+ * every path that reports none.
772
+ *
773
+ * On a completed app-server turn the two agree, because a turn whose
774
+ * reported model differed from the requested one was refused before it
775
+ * ran (`model_mismatch`) — so a completed record's `model` is what codex
776
+ * ran, and the record can no longer say one model while another was
777
+ * billed. They differ only on such a refused record, and where no model
778
+ * was requested at all. Gated to [`FIRST_MODEL_OBSERVATION_SCHEMA_VERSION`].
779
+ */
780
+ observed_model?: string | null | undefined;
667
781
  observed_tool_ms?: never | undefined;
668
782
  /**
669
783
  * The normalized approval mode requested for the run.
@@ -679,7 +793,7 @@ export type HistoryRecord = {
679
793
  * run's single prompt).
680
794
  */
681
795
  prompt: string;
682
- schema_version: "1.3" | "1.4" | "1.5" | "1.6" | "1.7";
796
+ schema_version: "1.3" | "1.4" | "1.5" | "1.6" | "1.7" | "1.8";
683
797
  /**
684
798
  * The oneharness session id this run belongs to (the history file's stem).
685
799
  */
@@ -766,7 +880,10 @@ export type HistoryRecord = {
766
880
  history_id: string;
767
881
  labels?: HistoryLabels6 | undefined;
768
882
  /**
769
- * The effective top-level model for the run, if any.
883
+ * The model this run **requested** — the value oneharness put on the
884
+ * harness's model flag or protocol frame — if any. Copied from
885
+ * [`RunResult::model`], so it keeps meaning the requested model even where
886
+ * `observed_model` below is present.
770
887
  */
771
888
  model: string | null;
772
889
  model_ms?: never | undefined;
@@ -775,6 +892,22 @@ export type HistoryRecord = {
775
892
  * every record so a reader can resolve a session by name from any line.
776
893
  */
777
894
  name: string;
895
+ /**
896
+ * The model the harness **itself** reported the conversation would run
897
+ * under, read off its own protocol before any token was spent — for codex
898
+ * over `app-server`, `result.model` of the `thread/start` /
899
+ * `thread/resume` response. Copied from [`RunResult::observed_model`]:
900
+ * never inferred and never copied from `model`, and omitted on the wire on
901
+ * every path that reports none.
902
+ *
903
+ * On a completed app-server turn the two agree, because a turn whose
904
+ * reported model differed from the requested one was refused before it
905
+ * ran (`model_mismatch`) — so a completed record's `model` is what codex
906
+ * ran, and the record can no longer say one model while another was
907
+ * billed. They differ only on such a refused record, and where no model
908
+ * was requested at all. Gated to [`FIRST_MODEL_OBSERVATION_SCHEMA_VERSION`].
909
+ */
910
+ observed_model?: string | null | undefined;
778
911
  observed_tool_ms?: never | undefined;
779
912
  /**
780
913
  * The normalized approval mode requested for the run.
@@ -889,7 +1022,10 @@ export type HistoryRecord = {
889
1022
  history_id: string;
890
1023
  labels?: HistoryLabels7 | undefined;
891
1024
  /**
892
- * The effective top-level model for the run, if any.
1025
+ * The model this run **requested** — the value oneharness put on the
1026
+ * harness's model flag or protocol frame — if any. Copied from
1027
+ * [`RunResult::model`], so it keeps meaning the requested model even where
1028
+ * `observed_model` below is present.
893
1029
  */
894
1030
  model: string | null;
895
1031
  model_ms?: never | undefined;
@@ -898,6 +1034,22 @@ export type HistoryRecord = {
898
1034
  * every record so a reader can resolve a session by name from any line.
899
1035
  */
900
1036
  name: string;
1037
+ /**
1038
+ * The model the harness **itself** reported the conversation would run
1039
+ * under, read off its own protocol before any token was spent — for codex
1040
+ * over `app-server`, `result.model` of the `thread/start` /
1041
+ * `thread/resume` response. Copied from [`RunResult::observed_model`]:
1042
+ * never inferred and never copied from `model`, and omitted on the wire on
1043
+ * every path that reports none.
1044
+ *
1045
+ * On a completed app-server turn the two agree, because a turn whose
1046
+ * reported model differed from the requested one was refused before it
1047
+ * ran (`model_mismatch`) — so a completed record's `model` is what codex
1048
+ * ran, and the record can no longer say one model while another was
1049
+ * billed. They differ only on such a refused record, and where no model
1050
+ * was requested at all. Gated to [`FIRST_MODEL_OBSERVATION_SCHEMA_VERSION`].
1051
+ */
1052
+ observed_model?: string | null | undefined;
901
1053
  observed_tool_ms?: never | undefined;
902
1054
  /**
903
1055
  * The normalized approval mode requested for the run.
@@ -1000,7 +1152,10 @@ export type HistoryRecord = {
1000
1152
  history_id: string;
1001
1153
  labels?: HistoryLabels8 | undefined;
1002
1154
  /**
1003
- * The effective top-level model for the run, if any.
1155
+ * The model this run **requested** — the value oneharness put on the
1156
+ * harness's model flag or protocol frame — if any. Copied from
1157
+ * [`RunResult::model`], so it keeps meaning the requested model even where
1158
+ * `observed_model` below is present.
1004
1159
  */
1005
1160
  model: string | null;
1006
1161
  model_ms?: number | null | undefined;
@@ -1009,6 +1164,22 @@ export type HistoryRecord = {
1009
1164
  * every record so a reader can resolve a session by name from any line.
1010
1165
  */
1011
1166
  name: string;
1167
+ /**
1168
+ * The model the harness **itself** reported the conversation would run
1169
+ * under, read off its own protocol before any token was spent — for codex
1170
+ * over `app-server`, `result.model` of the `thread/start` /
1171
+ * `thread/resume` response. Copied from [`RunResult::observed_model`]:
1172
+ * never inferred and never copied from `model`, and omitted on the wire on
1173
+ * every path that reports none.
1174
+ *
1175
+ * On a completed app-server turn the two agree, because a turn whose
1176
+ * reported model differed from the requested one was refused before it
1177
+ * ran (`model_mismatch`) — so a completed record's `model` is what codex
1178
+ * ran, and the record can no longer say one model while another was
1179
+ * billed. They differ only on such a refused record, and where no model
1180
+ * was requested at all. Gated to [`FIRST_MODEL_OBSERVATION_SCHEMA_VERSION`].
1181
+ */
1182
+ observed_model?: string | null | undefined;
1012
1183
  /**
1013
1184
  * Union of tool intervals observed at the stdout pipe. Unlike `tool_ms`,
1014
1185
  * this is not provider-measured and has no model-latency counterpart.
@@ -1095,7 +1266,7 @@ export type TimingSource = "provider_measured" | "stdout_observed";
1095
1266
  * the report, history) one definition to share instead of scattered string
1096
1267
  * literals.
1097
1268
  */
1098
- export type FailureKind = "auth" | "rate_limit" | "model_not_found" | "quota" | "session_not_found" | "tool_deferred" | "untrusted_directory" | "input_too_large";
1269
+ export type FailureKind = "auth" | "rate_limit" | "model_not_found" | "quota" | "session_not_found" | "tool_deferred" | "untrusted_directory" | "input_too_large" | "model_mismatch";
1099
1270
  /**
1100
1271
  * The outcome of attempting to run one harness.
1101
1272
  */
@@ -1125,7 +1296,7 @@ export type HistoryRecords = (({
1125
1296
  [k: string]: unknown;
1126
1297
  } | ({
1127
1298
  error: string;
1128
- schema_version?: "1.3" | "1.4" | "1.5" | "1.6" | "1.7" | undefined;
1299
+ schema_version?: "1.3" | "1.4" | "1.5" | "1.6" | "1.7" | "1.8" | undefined;
1129
1300
  [k: string]: unknown;
1130
1301
  } & ({
1131
1302
  status?: "nonzero" | "timeout" | "cancelled" | "spawn-error" | "skipped" | undefined;
@@ -1137,27 +1308,40 @@ export type HistoryRecords = (({
1137
1308
  work?: null | undefined;
1138
1309
  [k: string]: unknown;
1139
1310
  } | {
1140
- schema_version?: "1.7" | undefined;
1311
+ schema_version?: "1.7" | "1.8" | undefined;
1141
1312
  status?: "nonzero" | "timeout" | "cancelled" | undefined;
1142
1313
  work: "done" | "none";
1143
1314
  [k: string]: unknown;
1315
+ }) & ({
1316
+ observed_model?: null | undefined;
1317
+ [k: string]: unknown;
1318
+ } | {
1319
+ observed_model: string;
1320
+ schema_version?: "1.8" | undefined;
1321
+ [k: string]: unknown;
1144
1322
  }) & ({
1145
1323
  status?: "ok" | "nonzero" | "timeout" | "spawn-error" | "skipped" | "planned" | undefined;
1146
1324
  [k: string]: unknown;
1147
1325
  } | {
1148
- schema_version?: "1.4" | "1.5" | "1.6" | "1.7" | undefined;
1326
+ schema_version?: "1.4" | "1.5" | "1.6" | "1.7" | "1.8" | undefined;
1149
1327
  [k: string]: unknown;
1150
1328
  }) & (({
1151
- failure_kind?: "auth" | "rate_limit" | "model_not_found" | "quota" | "tool_deferred" | "untrusted_directory" | "input_too_large" | null;
1329
+ failure_kind?: "auth" | "rate_limit" | "model_not_found" | "quota" | "tool_deferred" | "untrusted_directory" | "input_too_large" | "model_mismatch" | null;
1330
+ [k: string]: unknown;
1331
+ } | {
1332
+ schema_version?: "1.5" | "1.6" | "1.7" | "1.8" | undefined;
1333
+ [k: string]: unknown;
1334
+ }) & ({
1335
+ failure_kind?: "auth" | "rate_limit" | "model_not_found" | "quota" | "session_not_found" | "tool_deferred" | "model_mismatch" | null;
1152
1336
  [k: string]: unknown;
1153
1337
  } | {
1154
- schema_version?: "1.5" | "1.6" | "1.7" | undefined;
1338
+ schema_version?: "1.6" | "1.7" | "1.8" | undefined;
1155
1339
  [k: string]: unknown;
1156
1340
  }) & ({
1157
- failure_kind?: "auth" | "rate_limit" | "model_not_found" | "quota" | "session_not_found" | "tool_deferred" | null;
1341
+ failure_kind?: "auth" | "rate_limit" | "model_not_found" | "quota" | "session_not_found" | "tool_deferred" | "untrusted_directory" | "input_too_large" | null;
1158
1342
  [k: string]: unknown;
1159
1343
  } | {
1160
- schema_version?: "1.6" | "1.7" | undefined;
1344
+ schema_version?: "1.8" | undefined;
1161
1345
  [k: string]: unknown;
1162
1346
  })) & HistoryRecord)[];
1163
1347
  /**