@oneharness/sdk 0.11.4 → 0.12.1

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.
@@ -8,7 +8,7 @@ export type HistoryRecord = ({
8
8
  [k: string]: unknown;
9
9
  } | ({
10
10
  error: string;
11
- schema_version?: "1.3" | "1.4" | "1.5" | "1.6" | "1.7" | undefined;
11
+ schema_version?: "1.3" | "1.4" | "1.5" | "1.6" | "1.7" | "1.8" | undefined;
12
12
  [k: string]: unknown;
13
13
  } & ({
14
14
  status?: "nonzero" | "timeout" | "cancelled" | "spawn-error" | "skipped" | undefined;
@@ -20,27 +20,40 @@ export type HistoryRecord = ({
20
20
  work?: null | undefined;
21
21
  [k: string]: unknown;
22
22
  } | {
23
- schema_version?: "1.7" | undefined;
23
+ schema_version?: "1.7" | "1.8" | undefined;
24
24
  status?: "nonzero" | "timeout" | "cancelled" | undefined;
25
25
  work: "done" | "none";
26
26
  [k: string]: unknown;
27
+ }) & ({
28
+ observed_model?: null | undefined;
29
+ [k: string]: unknown;
30
+ } | {
31
+ observed_model: string;
32
+ schema_version?: "1.8" | undefined;
33
+ [k: string]: unknown;
27
34
  }) & ({
28
35
  status?: "ok" | "nonzero" | "timeout" | "spawn-error" | "skipped" | "planned" | undefined;
29
36
  [k: string]: unknown;
30
37
  } | {
31
- schema_version?: "1.4" | "1.5" | "1.6" | "1.7" | undefined;
38
+ schema_version?: "1.4" | "1.5" | "1.6" | "1.7" | "1.8" | undefined;
32
39
  [k: string]: unknown;
33
40
  }) & (({
34
- failure_kind?: "auth" | "rate_limit" | "model_not_found" | "quota" | "tool_deferred" | "untrusted_directory" | "input_too_large" | null;
41
+ failure_kind?: "auth" | "rate_limit" | "model_not_found" | "quota" | "tool_deferred" | "untrusted_directory" | "input_too_large" | "model_mismatch" | null;
42
+ [k: string]: unknown;
43
+ } | {
44
+ schema_version?: "1.5" | "1.6" | "1.7" | "1.8" | undefined;
45
+ [k: string]: unknown;
46
+ }) & ({
47
+ failure_kind?: "auth" | "rate_limit" | "model_not_found" | "quota" | "session_not_found" | "tool_deferred" | "model_mismatch" | null;
35
48
  [k: string]: unknown;
36
49
  } | {
37
- schema_version?: "1.5" | "1.6" | "1.7" | undefined;
50
+ schema_version?: "1.6" | "1.7" | "1.8" | undefined;
38
51
  [k: string]: unknown;
39
52
  }) & ({
40
- failure_kind?: "auth" | "rate_limit" | "model_not_found" | "quota" | "session_not_found" | "tool_deferred" | null;
53
+ failure_kind?: "auth" | "rate_limit" | "model_not_found" | "quota" | "session_not_found" | "tool_deferred" | "untrusted_directory" | "input_too_large" | null;
41
54
  [k: string]: unknown;
42
55
  } | {
43
- schema_version?: "1.6" | "1.7" | undefined;
56
+ schema_version?: "1.8" | undefined;
44
57
  [k: string]: unknown;
45
58
  })) & ({
46
59
  duration_ms: number;
@@ -113,7 +126,10 @@ export type HistoryRecord = ({
113
126
  history_id: string;
114
127
  labels?: HistoryLabels | undefined;
115
128
  /**
116
- * The effective top-level model for the run, if any.
129
+ * The model this run **requested** — the value oneharness put on the
130
+ * harness's model flag or protocol frame — if any. Copied from
131
+ * [`RunResult::model`], so it keeps meaning the requested model even where
132
+ * `observed_model` below is present.
117
133
  */
118
134
  model: string | null;
119
135
  model_ms: number;
@@ -122,6 +138,22 @@ export type HistoryRecord = ({
122
138
  * every record so a reader can resolve a session by name from any line.
123
139
  */
124
140
  name: string;
141
+ /**
142
+ * The model the harness **itself** reported the conversation would run
143
+ * under, read off its own protocol before any token was spent — for codex
144
+ * over `app-server`, `result.model` of the `thread/start` /
145
+ * `thread/resume` response. Copied from [`RunResult::observed_model`]:
146
+ * never inferred and never copied from `model`, and omitted on the wire on
147
+ * every path that reports none.
148
+ *
149
+ * On a completed app-server turn the two agree, because a turn whose
150
+ * reported model differed from the requested one was refused before it
151
+ * ran (`model_mismatch`) — so a completed record's `model` is what codex
152
+ * ran, and the record can no longer say one model while another was
153
+ * billed. They differ only on such a refused record, and where no model
154
+ * was requested at all. Gated to [`FIRST_MODEL_OBSERVATION_SCHEMA_VERSION`].
155
+ */
156
+ observed_model?: string | null | undefined;
125
157
  observed_tool_ms?: never | undefined;
126
158
  /**
127
159
  * The normalized approval mode requested for the run.
@@ -137,7 +169,7 @@ export type HistoryRecord = ({
137
169
  * run's single prompt).
138
170
  */
139
171
  prompt: string;
140
- schema_version: "1.2" | "1.3" | "1.4" | "1.5" | "1.6" | "1.7";
172
+ schema_version: "1.2" | "1.3" | "1.4" | "1.5" | "1.6" | "1.7" | "1.8";
141
173
  /**
142
174
  * The oneharness session id this run belongs to (the history file's stem).
143
175
  */
@@ -255,7 +287,10 @@ export type HistoryRecord = ({
255
287
  history_id: string;
256
288
  labels?: HistoryLabels1 | undefined;
257
289
  /**
258
- * The effective top-level model for the run, if any.
290
+ * The model this run **requested** — the value oneharness put on the
291
+ * harness's model flag or protocol frame — if any. Copied from
292
+ * [`RunResult::model`], so it keeps meaning the requested model even where
293
+ * `observed_model` below is present.
259
294
  */
260
295
  model: string | null;
261
296
  model_ms: number;
@@ -264,6 +299,22 @@ export type HistoryRecord = ({
264
299
  * every record so a reader can resolve a session by name from any line.
265
300
  */
266
301
  name: string;
302
+ /**
303
+ * The model the harness **itself** reported the conversation would run
304
+ * under, read off its own protocol before any token was spent — for codex
305
+ * over `app-server`, `result.model` of the `thread/start` /
306
+ * `thread/resume` response. Copied from [`RunResult::observed_model`]:
307
+ * never inferred and never copied from `model`, and omitted on the wire on
308
+ * every path that reports none.
309
+ *
310
+ * On a completed app-server turn the two agree, because a turn whose
311
+ * reported model differed from the requested one was refused before it
312
+ * ran (`model_mismatch`) — so a completed record's `model` is what codex
313
+ * ran, and the record can no longer say one model while another was
314
+ * billed. They differ only on such a refused record, and where no model
315
+ * was requested at all. Gated to [`FIRST_MODEL_OBSERVATION_SCHEMA_VERSION`].
316
+ */
317
+ observed_model?: string | null | undefined;
267
318
  observed_tool_ms?: never | undefined;
268
319
  /**
269
320
  * The normalized approval mode requested for the run.
@@ -375,7 +426,10 @@ export type HistoryRecord = ({
375
426
  history_id: string;
376
427
  labels?: HistoryLabels2 | undefined;
377
428
  /**
378
- * The effective top-level model for the run, if any.
429
+ * The model this run **requested** — the value oneharness put on the
430
+ * harness's model flag or protocol frame — if any. Copied from
431
+ * [`RunResult::model`], so it keeps meaning the requested model even where
432
+ * `observed_model` below is present.
379
433
  */
380
434
  model: string | null;
381
435
  model_ms?: never | undefined;
@@ -384,6 +438,22 @@ export type HistoryRecord = ({
384
438
  * every record so a reader can resolve a session by name from any line.
385
439
  */
386
440
  name: string;
441
+ /**
442
+ * The model the harness **itself** reported the conversation would run
443
+ * under, read off its own protocol before any token was spent — for codex
444
+ * over `app-server`, `result.model` of the `thread/start` /
445
+ * `thread/resume` response. Copied from [`RunResult::observed_model`]:
446
+ * never inferred and never copied from `model`, and omitted on the wire on
447
+ * every path that reports none.
448
+ *
449
+ * On a completed app-server turn the two agree, because a turn whose
450
+ * reported model differed from the requested one was refused before it
451
+ * ran (`model_mismatch`) — so a completed record's `model` is what codex
452
+ * ran, and the record can no longer say one model while another was
453
+ * billed. They differ only on such a refused record, and where no model
454
+ * was requested at all. Gated to [`FIRST_MODEL_OBSERVATION_SCHEMA_VERSION`].
455
+ */
456
+ observed_model?: string | null | undefined;
387
457
  observed_tool_ms?: never | undefined;
388
458
  /**
389
459
  * The normalized approval mode requested for the run.
@@ -399,7 +469,7 @@ export type HistoryRecord = ({
399
469
  * run's single prompt).
400
470
  */
401
471
  prompt: string;
402
- schema_version: "1.2" | "1.3" | "1.4" | "1.5" | "1.6" | "1.7";
472
+ schema_version: "1.2" | "1.3" | "1.4" | "1.5" | "1.6" | "1.7" | "1.8";
403
473
  /**
404
474
  * The oneharness session id this run belongs to (the history file's stem).
405
475
  */
@@ -483,7 +553,10 @@ export type HistoryRecord = ({
483
553
  history_id: string;
484
554
  labels?: HistoryLabels3 | undefined;
485
555
  /**
486
- * The effective top-level model for the run, if any.
556
+ * The model this run **requested** — the value oneharness put on the
557
+ * harness's model flag or protocol frame — if any. Copied from
558
+ * [`RunResult::model`], so it keeps meaning the requested model even where
559
+ * `observed_model` below is present.
487
560
  */
488
561
  model: string | null;
489
562
  model_ms?: never | undefined;
@@ -492,6 +565,22 @@ export type HistoryRecord = ({
492
565
  * every record so a reader can resolve a session by name from any line.
493
566
  */
494
567
  name: string;
568
+ /**
569
+ * The model the harness **itself** reported the conversation would run
570
+ * under, read off its own protocol before any token was spent — for codex
571
+ * over `app-server`, `result.model` of the `thread/start` /
572
+ * `thread/resume` response. Copied from [`RunResult::observed_model`]:
573
+ * never inferred and never copied from `model`, and omitted on the wire on
574
+ * every path that reports none.
575
+ *
576
+ * On a completed app-server turn the two agree, because a turn whose
577
+ * reported model differed from the requested one was refused before it
578
+ * ran (`model_mismatch`) — so a completed record's `model` is what codex
579
+ * ran, and the record can no longer say one model while another was
580
+ * billed. They differ only on such a refused record, and where no model
581
+ * was requested at all. Gated to [`FIRST_MODEL_OBSERVATION_SCHEMA_VERSION`].
582
+ */
583
+ observed_model?: string | null | undefined;
495
584
  observed_tool_ms: number;
496
585
  /**
497
586
  * The normalized approval mode requested for the run.
@@ -507,7 +596,7 @@ export type HistoryRecord = ({
507
596
  * run's single prompt).
508
597
  */
509
598
  prompt: string;
510
- schema_version: "1.2" | "1.3" | "1.4" | "1.5" | "1.6" | "1.7";
599
+ schema_version: "1.2" | "1.3" | "1.4" | "1.5" | "1.6" | "1.7" | "1.8";
511
600
  /**
512
601
  * The oneharness session id this run belongs to (the history file's stem).
513
602
  */
@@ -591,7 +680,10 @@ export type HistoryRecord = ({
591
680
  history_id: string;
592
681
  labels?: HistoryLabels4 | undefined;
593
682
  /**
594
- * The effective top-level model for the run, if any.
683
+ * The model this run **requested** — the value oneharness put on the
684
+ * harness's model flag or protocol frame — if any. Copied from
685
+ * [`RunResult::model`], so it keeps meaning the requested model even where
686
+ * `observed_model` below is present.
595
687
  */
596
688
  model: string | null;
597
689
  model_ms?: never | undefined;
@@ -600,6 +692,22 @@ export type HistoryRecord = ({
600
692
  * every record so a reader can resolve a session by name from any line.
601
693
  */
602
694
  name: string;
695
+ /**
696
+ * The model the harness **itself** reported the conversation would run
697
+ * under, read off its own protocol before any token was spent — for codex
698
+ * over `app-server`, `result.model` of the `thread/start` /
699
+ * `thread/resume` response. Copied from [`RunResult::observed_model`]:
700
+ * never inferred and never copied from `model`, and omitted on the wire on
701
+ * every path that reports none.
702
+ *
703
+ * On a completed app-server turn the two agree, because a turn whose
704
+ * reported model differed from the requested one was refused before it
705
+ * ran (`model_mismatch`) — so a completed record's `model` is what codex
706
+ * ran, and the record can no longer say one model while another was
707
+ * billed. They differ only on such a refused record, and where no model
708
+ * was requested at all. Gated to [`FIRST_MODEL_OBSERVATION_SCHEMA_VERSION`].
709
+ */
710
+ observed_model?: string | null | undefined;
603
711
  observed_tool_ms?: never | undefined;
604
712
  /**
605
713
  * The normalized approval mode requested for the run.
@@ -615,7 +723,7 @@ export type HistoryRecord = ({
615
723
  * run's single prompt).
616
724
  */
617
725
  prompt: string;
618
- schema_version: "1.2" | "1.3" | "1.4" | "1.5" | "1.6" | "1.7";
726
+ schema_version: "1.2" | "1.3" | "1.4" | "1.5" | "1.6" | "1.7" | "1.8";
619
727
  /**
620
728
  * The oneharness session id this run belongs to (the history file's stem).
621
729
  */
@@ -699,7 +807,10 @@ export type HistoryRecord = ({
699
807
  history_id: string;
700
808
  labels?: HistoryLabels5 | undefined;
701
809
  /**
702
- * The effective top-level model for the run, if any.
810
+ * The model this run **requested** — the value oneharness put on the
811
+ * harness's model flag or protocol frame — if any. Copied from
812
+ * [`RunResult::model`], so it keeps meaning the requested model even where
813
+ * `observed_model` below is present.
703
814
  */
704
815
  model: string | null;
705
816
  model_ms?: never | undefined;
@@ -708,6 +819,22 @@ export type HistoryRecord = ({
708
819
  * every record so a reader can resolve a session by name from any line.
709
820
  */
710
821
  name: string;
822
+ /**
823
+ * The model the harness **itself** reported the conversation would run
824
+ * under, read off its own protocol before any token was spent — for codex
825
+ * over `app-server`, `result.model` of the `thread/start` /
826
+ * `thread/resume` response. Copied from [`RunResult::observed_model`]:
827
+ * never inferred and never copied from `model`, and omitted on the wire on
828
+ * every path that reports none.
829
+ *
830
+ * On a completed app-server turn the two agree, because a turn whose
831
+ * reported model differed from the requested one was refused before it
832
+ * ran (`model_mismatch`) — so a completed record's `model` is what codex
833
+ * ran, and the record can no longer say one model while another was
834
+ * billed. They differ only on such a refused record, and where no model
835
+ * was requested at all. Gated to [`FIRST_MODEL_OBSERVATION_SCHEMA_VERSION`].
836
+ */
837
+ observed_model?: string | null | undefined;
711
838
  observed_tool_ms?: never | undefined;
712
839
  /**
713
840
  * The normalized approval mode requested for the run.
@@ -723,7 +850,7 @@ export type HistoryRecord = ({
723
850
  * run's single prompt).
724
851
  */
725
852
  prompt: string;
726
- schema_version: "1.3" | "1.4" | "1.5" | "1.6" | "1.7";
853
+ schema_version: "1.3" | "1.4" | "1.5" | "1.6" | "1.7" | "1.8";
727
854
  /**
728
855
  * The oneharness session id this run belongs to (the history file's stem).
729
856
  */
@@ -810,7 +937,10 @@ export type HistoryRecord = ({
810
937
  history_id: string;
811
938
  labels?: HistoryLabels6 | undefined;
812
939
  /**
813
- * The effective top-level model for the run, if any.
940
+ * The model this run **requested** — the value oneharness put on the
941
+ * harness's model flag or protocol frame — if any. Copied from
942
+ * [`RunResult::model`], so it keeps meaning the requested model even where
943
+ * `observed_model` below is present.
814
944
  */
815
945
  model: string | null;
816
946
  model_ms?: never | undefined;
@@ -819,6 +949,22 @@ export type HistoryRecord = ({
819
949
  * every record so a reader can resolve a session by name from any line.
820
950
  */
821
951
  name: string;
952
+ /**
953
+ * The model the harness **itself** reported the conversation would run
954
+ * under, read off its own protocol before any token was spent — for codex
955
+ * over `app-server`, `result.model` of the `thread/start` /
956
+ * `thread/resume` response. Copied from [`RunResult::observed_model`]:
957
+ * never inferred and never copied from `model`, and omitted on the wire on
958
+ * every path that reports none.
959
+ *
960
+ * On a completed app-server turn the two agree, because a turn whose
961
+ * reported model differed from the requested one was refused before it
962
+ * ran (`model_mismatch`) — so a completed record's `model` is what codex
963
+ * ran, and the record can no longer say one model while another was
964
+ * billed. They differ only on such a refused record, and where no model
965
+ * was requested at all. Gated to [`FIRST_MODEL_OBSERVATION_SCHEMA_VERSION`].
966
+ */
967
+ observed_model?: string | null | undefined;
822
968
  observed_tool_ms?: never | undefined;
823
969
  /**
824
970
  * The normalized approval mode requested for the run.
@@ -933,7 +1079,10 @@ export type HistoryRecord = ({
933
1079
  history_id: string;
934
1080
  labels?: HistoryLabels7 | undefined;
935
1081
  /**
936
- * The effective top-level model for the run, if any.
1082
+ * The model this run **requested** — the value oneharness put on the
1083
+ * harness's model flag or protocol frame — if any. Copied from
1084
+ * [`RunResult::model`], so it keeps meaning the requested model even where
1085
+ * `observed_model` below is present.
937
1086
  */
938
1087
  model: string | null;
939
1088
  model_ms?: never | undefined;
@@ -942,6 +1091,22 @@ export type HistoryRecord = ({
942
1091
  * every record so a reader can resolve a session by name from any line.
943
1092
  */
944
1093
  name: string;
1094
+ /**
1095
+ * The model the harness **itself** reported the conversation would run
1096
+ * under, read off its own protocol before any token was spent — for codex
1097
+ * over `app-server`, `result.model` of the `thread/start` /
1098
+ * `thread/resume` response. Copied from [`RunResult::observed_model`]:
1099
+ * never inferred and never copied from `model`, and omitted on the wire on
1100
+ * every path that reports none.
1101
+ *
1102
+ * On a completed app-server turn the two agree, because a turn whose
1103
+ * reported model differed from the requested one was refused before it
1104
+ * ran (`model_mismatch`) — so a completed record's `model` is what codex
1105
+ * ran, and the record can no longer say one model while another was
1106
+ * billed. They differ only on such a refused record, and where no model
1107
+ * was requested at all. Gated to [`FIRST_MODEL_OBSERVATION_SCHEMA_VERSION`].
1108
+ */
1109
+ observed_model?: string | null | undefined;
945
1110
  observed_tool_ms?: never | undefined;
946
1111
  /**
947
1112
  * The normalized approval mode requested for the run.
@@ -1044,7 +1209,10 @@ export type HistoryRecord = ({
1044
1209
  history_id: string;
1045
1210
  labels?: HistoryLabels8 | undefined;
1046
1211
  /**
1047
- * The effective top-level model for the run, if any.
1212
+ * The model this run **requested** — the value oneharness put on the
1213
+ * harness's model flag or protocol frame — if any. Copied from
1214
+ * [`RunResult::model`], so it keeps meaning the requested model even where
1215
+ * `observed_model` below is present.
1048
1216
  */
1049
1217
  model: string | null;
1050
1218
  model_ms?: number | null | undefined;
@@ -1053,6 +1221,22 @@ export type HistoryRecord = ({
1053
1221
  * every record so a reader can resolve a session by name from any line.
1054
1222
  */
1055
1223
  name: string;
1224
+ /**
1225
+ * The model the harness **itself** reported the conversation would run
1226
+ * under, read off its own protocol before any token was spent — for codex
1227
+ * over `app-server`, `result.model` of the `thread/start` /
1228
+ * `thread/resume` response. Copied from [`RunResult::observed_model`]:
1229
+ * never inferred and never copied from `model`, and omitted on the wire on
1230
+ * every path that reports none.
1231
+ *
1232
+ * On a completed app-server turn the two agree, because a turn whose
1233
+ * reported model differed from the requested one was refused before it
1234
+ * ran (`model_mismatch`) — so a completed record's `model` is what codex
1235
+ * ran, and the record can no longer say one model while another was
1236
+ * billed. They differ only on such a refused record, and where no model
1237
+ * was requested at all. Gated to [`FIRST_MODEL_OBSERVATION_SCHEMA_VERSION`].
1238
+ */
1239
+ observed_model?: string | null | undefined;
1056
1240
  /**
1057
1241
  * Union of tool intervals observed at the stdout pipe. Unlike `tool_ms`,
1058
1242
  * this is not provider-measured and has no model-latency counterpart.
@@ -1139,7 +1323,7 @@ export type TimingSource = "provider_measured" | "stdout_observed";
1139
1323
  * the report, history) one definition to share instead of scattered string
1140
1324
  * literals.
1141
1325
  */
1142
- export type FailureKind = "auth" | "rate_limit" | "model_not_found" | "quota" | "session_not_found" | "tool_deferred" | "untrusted_directory" | "input_too_large";
1326
+ export type FailureKind = "auth" | "rate_limit" | "model_not_found" | "quota" | "session_not_found" | "tool_deferred" | "untrusted_directory" | "input_too_large" | "model_mismatch";
1143
1327
  /**
1144
1328
  * The outcome of attempting to run one harness.
1145
1329
  */
@@ -79,7 +79,7 @@ export type ControlVerb = "interrupt";
79
79
  * new variant is a report `schema_version` bump like any other enum value, since
80
80
  * a consumer matching exhaustively learns of it only from the version.
81
81
  */
82
- export type FallThroughReason = "not-installed" | "spawn-error" | "auth" | "quota" | "session-not-found" | "untrusted-directory" | "input-too-large" | "model-not-found" | "rate-limit";
82
+ export type FallThroughReason = "not-installed" | "spawn-error" | "auth" | "quota" | "session-not-found" | "untrusted-directory" | "input-too-large" | "model-mismatch" | "model-not-found" | "rate-limit";
83
83
  /**
84
84
  * The normalized, closed set of failure reasons oneharness can classify from a
85
85
  * harness's output. It is the single source for the `failure_kind` contract
@@ -91,7 +91,7 @@ export type FallThroughReason = "not-installed" | "spawn-error" | "auth" | "quot
91
91
  * the report, history) one definition to share instead of scattered string
92
92
  * literals.
93
93
  */
94
- export type FailureKind = "auth" | "rate_limit" | "model_not_found" | "quota" | "session_not_found" | "tool_deferred" | "untrusted_directory" | "input_too_large";
94
+ export type FailureKind = "auth" | "rate_limit" | "model_not_found" | "quota" | "session_not_found" | "tool_deferred" | "untrusted_directory" | "input_too_large" | "model_mismatch";
95
95
  /**
96
96
  * How a harness emits its result, which decides how `text` is extracted.
97
97
  *
@@ -382,7 +382,8 @@ export interface FallbackReport {
382
382
  * The candidates fallen through because they could not run the task at all,
383
383
  * in priority order, each with why (`not-installed`, `spawn-error`, `auth`,
384
384
  * `quota`, `session-not-found`, `untrusted-directory`, `input-too-large`,
385
- * and — on a model fan-out — `model-not-found` / `rate-limit`; see
385
+ * `model-mismatch`, and — on a model fan-out — `model-not-found` /
386
+ * `rate-limit`; see
386
387
  * [`crate::domain::fallback::startup_failure_reason`]).
387
388
  */
388
389
  fell_through: FallThrough[];
@@ -397,13 +398,16 @@ export interface FallbackReport {
397
398
  * [`RunResult::work`] read [`RunWork::None`] on a failure no classifier
398
399
  * recognized.
399
400
  *
400
- * The chain still stops there, deliberately: re-running a task that may
401
- * genuinely have failed for free would burn the next identity's quota on
402
- * the same failure, which is worse than stopping (see
401
+ * The chain still stops there, deliberately — decided, not inherited:
402
+ * empty accounting is the absence of work evidence, not proof nothing was
403
+ * spent, so handing the candidate on could bill a task twice (the decision
404
+ * and its reasoning are stated once, at
403
405
  * [`crate::domain::fallback::startup_failure_reason`]). What this flag adds
404
406
  * is the *attribution* — without it a candidate that never got started reads
405
407
  * in the report exactly like one that tried the task and failed it, and the
406
- * remaining candidates look untried for a reason nobody can name.
408
+ * remaining candidates look untried for a reason nobody can name — and the
409
+ * failure summary carries the candidate's own words beside it, so the
410
+ * reader left holding that one line can act on the cause.
407
411
  *
408
412
  * `false` whenever `ran` is `null` (no candidate ran at all — every one is
409
413
  * in `fell_through`, each with its reason).
@@ -489,7 +493,8 @@ export interface RunResult {
489
493
  * Best-effort failure reason; `null` when unclassified. Distinct from
490
494
  * `status`, which records oneharness's relationship to the process. Two
491
495
  * families: coarse reasons for a non-zero run (`auth`, `rate_limit`,
492
- * `model_not_found`, `quota`, `session_not_found`), and `tool_deferred` — a run that exited
496
+ * `model_not_found`, `quota`, `session_not_found`, `untrusted_directory`,
497
+ * `input_too_large`, `model_mismatch`), and `tool_deferred` — a run that exited
493
498
  * *cleanly* but only deferred a builtin tool call instead of executing it
494
499
  * (Claude Code bridge/managed deployments), so it did no useful work. The
495
500
  * deferred case is the only `failure_kind` that can appear on a `status: ok`
@@ -519,6 +524,17 @@ export interface RunResult {
519
524
  * without parsing the argv.
520
525
  */
521
526
  model: string | null;
527
+ /**
528
+ * The model the harness **itself** reported the conversation would run
529
+ * under, read off its own protocol before any token was spent — for codex
530
+ * over `app-server`, `result.model` of the `thread/start` / `thread/resume`
531
+ * response. `null` on every path that reports none, which today is every
532
+ * path but codex's app-server. Never inferred and never copied from
533
+ * `model`: where both are set they are the requested model and the served
534
+ * one, and a difference between them is exactly the `model_mismatch`
535
+ * refusal, which this field then names the other half of.
536
+ */
537
+ observed_model: string | null;
522
538
  output_format: OutputFormat;
523
539
  /**
524
540
  * The prompt this result ran, set only on a **batch** run (one harness