
Do not treat the reply as something a run produced, and do not ask the model which run it was, until you can name the run. Tonight, three proofs, from a log you stored. Name the run that thread started: the run id, the status, and the assistant id. Show a different run whose id, or whose assistant, is not this one. Show that you stored the request, rather than asking the model to remember it. If the log does not keep the run, write that. A fluent answer is not an id.
This is the run on one thread. It is not the file. Which file did that message attach? is the file id, the purpose, and the bytes. A message can be stored while run_id is null, and a run can complete while the attachment list is empty. It is not the schema. Which schema did that call require? is the schema name and the required keys. A schema can be strict while the run status is a different field. It is not the store. Which store did that file join? is the store id, the file id, and the status. A store can be attached while this run id was never written down. It is not a workflow run. Which workflow did that run execute? is the workflow and the job. A job id is not a thread run id. It is not the quote a customer accepted, and it is not the milestone an issue joined.
None of what follows is a score for this product, and none of it is a promise that a benchmark's judge saw your log. The fields below are one vendor's current description of a thread run, and the retrieve example and the list example are not the same object. The counts below that are a 2026 benchmark of other people's tool-calling traces. A token total on an example is not a census of your calls. A judge that never opened your run cannot name the status on the run you stored tonight. They do tell you which numbers people mix up when they try to sound precise about a trace they have not opened.
OpenAI's retrieve example prints id run_abc123, object thread.run, created_at 1699075072, assistant_id asst_abc123, thread_id thread_abc123, and status completed. run_abc123 is 10 characters. thread_abc123 is 13 characters. asst_abc123 is 11 characters. 10 is not 13, and 13 is not 11. started_at is 1699075072, the same integer as created_at, so that gap is 0. completed_at is 1699075073. completed_at minus created_at is 1 second. 1 is not 0. expires_at, cancelled_at, and failed_at are null. instructions is null. incomplete_details is null. The tools array has one object, type code_interpreter. usage prints prompt_tokens 123, completion_tokens 456, and total_tokens 579. 123 plus 456 is 579. That addition matches. It does not make 579 a run id. temperature is 1.0. top_p is 1.0. max_prompt_tokens is 1000. max_completion_tokens is 1000. 579 is not 1000. 123 is not 1000. 456 is not 1000. truncation_strategy type is auto, and last_messages is null. response_format is auto. tool_choice is auto. parallel_tool_calls is true. model is gpt-4o. A model name is not a run id (OpenAI, Retrieve run).
The status names are nine, and the retrieve sample is only one of them. The status can be queued, in_progress, requires_action, cancelling, cancelled, failed, completed, incomplete, or expired. Nine names. completed is the retrieve sample. queued is not completed. incomplete is not failed. cancelled, with two els, is the spelling on this object. expires_at null is not status expired. The incomplete reason, when it is set, is max_completion_tokens or max_prompt_tokens. Two names. The retrieve sample's incomplete_details is null, so neither reason is stored there. A last_error code, when it is set, is server_error, rate_limit_exceeded, or invalid_prompt. Three names. The retrieve sample's last_error is null. Three error names are not nine statuses, and nine statuses are not 579 tokens. The list endpoint's limit can range from 1 to 100, and the default is 20. 20 is not 100. 1 is not 20.
The list example on the runs reference does not contain the retrieve object, even though its first_id is the retrieve id. The data array has one object. That object's id is the placeholder string id, 2 characters, not run_abc123. Its status is queued. Its created_at, expires_at, started_at, completed_at, cancelled_at, and failed_at are all 0. 0 is not 1699075072, and 0 is not null. incomplete_details.reason is max_completion_tokens, while the status is queued, not incomplete. usage prints prompt_tokens 0, completion_tokens 0, and total_tokens 0. 0 plus 0 is 0. That addition matches, and 0 is not 579. The reference says usage is null when the run is not in a terminal state. queued is not a terminal state, and the example still prints a usage object. temperature is 0. top_p is 0. 0 is not 1.0. max_prompt_tokens is 256. max_completion_tokens is 256. 256 is not 1000. truncation_strategy type is auto, and last_messages is 1. The retrieve example's last_messages is null. 1 is not null. The prose says last_messages is what you set when the type is last_messages. This example sets type auto and last_messages 1 on the same object. first_id is run_abc123. last_id is run_abc456. has_more is false. One object in data, and the first id is not the last id, and neither of those ids is the id field inside the object. Do not merge this list into the retrieve example because the first_id string matches (OpenAI, Runs).
The benchmark people quote when they want a judge score did not open this thread. Abhigya Verma, Amit Kumar Saha, Seganrasan Subramanian, and Sai Harshitha Aluru, at ServiceNow AI, present AgentJudgeBench: 3808 records, six DAG topologies, three difficulty tiers, five generators, and six judges. The introduction says those factors yield 321648 paired with-ground-truth and without-ground-truth evaluations. The appendix then prints a different product. It says 53608 times 6 judges times 2 conditions equals 643296 evaluation instances, called a theoretical maximum, and that 321648 is the count of unique tuples, each evaluated under both conditions. 53608 times 6 is 321648. That multiplication matches the unique-tuple line. 53608 times 6 times 2 is 643296. That multiplication matches the theoretical maximum. 321648 times 2 is also 643296. The introduction's 321648 and the appendix's 643296 are not the same count. Do not cite one as the other (Verma et al., AgentJudgeBench).
The record count does not produce the appendix's 53608. Five generators times three difficulties times 3808 records is 57120. 57120 is not 53608. 57120 minus 53608 is 3512. The page does not print 57120 or 3512. The appendix also says the structural tables are computed on unique records, collapsing the three difficulty rewrites, and the total row of that table is 3808. If 3808 is the unique pool and each record is expanded into three tiers, the expanded count is 11424. 3808 times 3 is 11424. The page does not print 11424. 11424 is not 53608, and 3808 is not a run id. A band of 77% to 82% on hard queries without ground truth is 5 points wide. 82 minus 77 is 5. The largest rubric lift they name is 6.5 percentage points. 6.5 is not 5. Chain-of-thought, they say, adds at most 0.3 percentage points. 0.3 is not 6.5. Ground truth reduces alignment by 1.5 points for one frontier judge and 3.9 for another. 1.5 is not 3.9. None of these is total_tokens 579.
The validation table does not say what the sentence next to it says. They sample 198 triplets, 33 per topology. Six topologies times 33 is 198. That product matches. On hard strictly harder than medium, the unanimity table prints all-yes 186, all-no 0, and mixed 12. 186 plus 0 plus 12 is 198. The addition matches. 186 divided by 198 is 0.9394, which rounds to 93.9%, the percent the table prints. The paragraph under the table says every single triplet is unanimously judged hard-strictly-harder-than-medium. 186 is not 198. 12 is not 0. Every single triplet would be 198 all-yes. The table does not say that. On medium strictly harder than easy, all-yes is 114, all-no is 1, and mixed is 83. 114 plus 1 plus 83 is 198. Unanimity, all-yes plus all-no, is 115. 115 divided by 198 is 0.5808, which rounds to 58.1%, the percent the table prints. All-yes alone is 114 divided by 198, which is 0.5758, and that rounds to 57.6%, not 58.1%. The earlier sentence says the easy-to-medium step is unanimously validated on only 58.1%. 58.1 is the column that includes the one all-no. 114 yeses are not 115 unanimous cells. Mixed 83 divided by 198 is 0.4192, which rounds to 41.9%. That percent matches the paraphrase share they describe. It is a share of 198 triplets, not a status on your run.
Do the three proofs on one real run, in the log that actually holds it. First, the binding. Copy the run id, the thread id, the assistant id, the status, and the usage if the status is terminal. If status is completed, write completed. Do not rewrite it as queued because a list example uses queued. If usage is null, write null. If the token fields are present, add prompt and completion and see whether the total matches. Do not copy 123, 456, and 579 because a sample prints them. Second, the other run. A different run, with a different id, or a different assistant, is not this one. A judge score on someone else's traces is not that second run. If you cannot show a run that is not this one, you have a counter, not a record. Third, the stored request. The id has to be in a log you kept. A model that describes its own run is not that log. If the only copy is a chat scrollback, write that.
Three moves feel like the proof and are a second problem. Cancelling the run, or starting another one, because the status was embarrassing, before you have copied the id. A new run gets a new id. It does not tell you which run the customer saw. Quoting 77% to 82% because it looks precise, while the run you were asked about is one object, and the 3808 records that produced that band had not opened your thread. Asking the model which of the nine statuses it was. The model will pick a plausible name. It will not open the log. A file you have not kept, while the customer is arguing about an attachment, is which file did that message attach?. Opening that screen does not name the run id.
The path is ordinary when an operator can open one customer's trace without opening the next customer's trace as the way to prove it. Haystack is one search layer across a customer's documents, data lakes, and repositories. The shape that matters here is one customer's documents, distinct from the next customer's. That case is not a run ledger. Nothing in that sentence is a headcount, a duration, or a result figure. If the only control on the screen searches every customer's threads together, you do not have this proof. You have a totals page.
There is a version of this afternoon where hiring the path is the wrong purchase. Nothing is in production, because the feature has not reached a customer. No model is being called. The request was not logged, so there is no run to name. A customer has already seen another customer's data. Naming an id does not close a leak. The wrong value was already a write. Or no metric was ever named, so a rescue would have nothing to move. The criteria for a system that is already in front of customers and still cannot show the run sit on the page for an AI pilot failed to reach production. That page is the symptom. It does not name this thread, and it does not turn 93.9% into a status.
When the reply is already in front of a customer and the log cannot name the run, the missing object is specific. The run id, the status, and the assistant, a different run that is not that one, and a stored request rather than a recollection. An AI pilot failed to reach production engagement is for the system that is already in front of customers and cannot yet show those three: audit in the first one to two weeks, finished in 8 to 12 weeks, scoped after the audit, unpaid if the agreed metric does not move, rollout behind a human-review gate. The run you failed to store tonight is the kind of case the harness has to include, or the next release will answer and still be unable to say which run produced it. The harness is AI evaluation and observability. An AI integration sprint is the shape where the acceptance sentence can require the run id on every stored call. If you do not yet know whether the pilot can be saved, a two-week AI readiness assessment hands you the findings either way. The free production-readiness diagnostic is the short way to see whether you are looking at a missing run, a null usage, or a system that has not reached a customer. Those are the terms. They are not 579, and they are not 321648.
The quote a customer accepted, and the milestone an issue joined, are different objects: which quote did that customer accept? and which milestone did that issue join?. Do not record either on this page. A quote id is not a run id. A milestone number is not a status. The assistant a thread named is a different object: which assistant did that thread name?. Do not record it here. An assistant id is not a run status. The text an audio file returned is a different object: which text did that audio return?. Do not record it here. A duration is not a run status.
Before you tell them the assistant finished the job, do the three proofs and write the status. Name the run, the status, and the assistant, or write that the log stored no run. Show a different run that is not that one. Show the stored request rather than a recollection. Do not ask the model which of the nine statuses it was, and do not cite a judge band in place of the id. A paper can tell you how often a table and a sentence disagree about the same triplets, including the 186 that is not 198. The binding is the run you can defend.
Questions
You stop treating the reply as something a run produced, and you stop asking the model which run it was, until you can name the run id, the status, and the assistant id, show a different run whose id or assistant is not this one, and show that you stored the request. If the log does not keep the run, write that.
No. A band on someone else's tool-calling traces is not the id on this run. A run you can defend is the id, the status, and the assistant on this stored call, or a written line that the log stored no run. 77 to 82 on one band is not status completed, and 579 tokens on an example is not your call.
When nothing is in production, when no model is being called, when the request was not logged, when a customer has already seen another customer's data, when the wrong value was already a write, or when no metric was ever named.
Related: AI pilot failed to reach production
Find this useful? Tell Google to show you more of it.
