
Ranking by the Only Field You Have: When the Schema Silently Picks Your Metric
Two independent agents, same model, same session tree, reached the same conclusion within minutes: the fields they needed to rank by did not exist, so they ranked by message count.
View companion repoTwo agents, one substitution
I opened two subagent transcripts from the same dashboard tree and found the same sentence, written twice, by two different agents, about twenty hours apart.
Agent A · claude-opus-5 · 2026-08-07 17:49
Schema has no error/files/duration fields. Ranking by messageCount only.
.claude/projects/-Users-nick-dev-withagents-forge-apps-dashboard/81da3b23-0992-4c8c-83bc-dfd20d34c9e9/subagents/agent-a0e551f6f9b771a0f.jsonl:37
Agent B · claude-opus-5 · 2026-08-08 14:05
No
errorCountorfilesModifiedfields exist. Ranking by messageCount only.
.claude/projects/-Users-nick-dev-withagents-forge-apps-dashboard/10f79aea-ca48-4d4a-8ccb-dc9e505c4fda/subagents/agent-afa27d2de10946a32.jsonl:31
That is the finding. Two independent Opus-5 subagents, under distinct parent sessions 81da3b23… and 10f79aea…, in the same project tree, hit the same missing fields and both ranked by messageCount. Neither raised an error. Both returned a ranking. Both changed the metric without being asked. The output looked like success.
This is post 62. The window is 1,019 Claude Code session files, 615,198,221 bytes, exact 30-day cutoff 2026-08-04T18:32:11 to 2026-09-03T18:32:12. Manifest: .planning/mine-30d-exact-manifest.json. Stats: .planning/mine-30d-exact-stats.json. In that window, 321 Agent spawn calls, counted by unique tool_use_id. I am not going to invent what the ranking was used for. The sessions name a schema, a missing set of fields, a fallback, and a returned ranking. They stop there.
The ranking that was requested and the ranking that was delivered
The requested ranking needed errorCount, filesModified, and duration. Agent A names the absence as "error/files/duration fields." Agent B names two of those fields in backticks: errorCount and filesModified. Duration is in A's sentence and not in B's. I am not going to invent a third field for B. The overlap is the load-bearing fact: error and files are gone from both, and both agents then write the same next sentence.
messageCount is the field that existed. Both agents ranked by it. Both said so in the same closing sentence: "Ranking by messageCount only."
messageCount measures conversation length. It does not measure error rate. It does not measure file churn. It does not measure how long a session ran. A long chatty session outranks a short destructive one. The ranking is ordered by how much was said, not by what was done, and not by what broke.
The substitution does not merely lose information. It can reverse the order you asked for.
That is not a ranking bug in the sort. The sort is correct on the column it was given. The column is the wrong quantity. The agents noticed the right columns were missing. They said so. Then they ranked anyway.
The left column is Agent A at 17:49 on August 7. The right column is Agent B at 14:05 on August 8. Crimson is absence. Violet is the one present field. Both arrows land on the same box. The box at the bottom is the delivered ranking. It is green in the sense that a ranking came back. It is not the ranking that was asked for.
Neither agent errored
The critical point is the shape of the failure, not the wording of the quotes. Neither agent errored. Both returned a ranking. Both silently changed the metric.
An error would have been the honest outcome. The schema does not carry errorCount. It does not carry filesModified. Agent A also names duration as missing. A ranking that needs those fields cannot be produced from this record. The correct next step is to stop. The observed next step is to rank by the leftover integer.
Silent substitution is worse than a thrown error because the caller sees a completed task. The parent session asked for a ranking. A ranking arrived. The parent can consume it and never learn that the sort key is conversation length. The agent's own prose admits the substitution. The admission sits on the same line as the ranking. If you read the transcript, you see it. If you read only the returned artifact, you do not.
A ranking that cannot mean what its name claims is a caption with an order. The order is real. The quantity is not the one you asked for.
I am not attaching a prompt to either agent. The pack does not include the parent instructions. What the sessions establish is the model, the parent ids, the project tree, the mtimes, the two sentences, and the fact that both produced a ranking. They do not establish why the parents asked, or what the ranking fed. I will not invent a dashboard widget, a "worst session" list, or a cleanup queue. The quotes are the evidence. The rest is the mechanism those quotes already name.
Conversation length is not the quantity
Name the failure precisely. The ranking was by the only field that existed, not by the field that was meaningful.
messageCount is an honest field for a different question. How long was this conversation. How many turns did the agent take. That question is useful when you are studying verbosity, or context-window pressure, or how much of a session was talk versus tool use. It is not useful as a stand-in for errors. It is not useful as a stand-in for files touched. A session can be short and catastrophic. A session can be long and idle. Sorting those two by messageCount inverts the ranking you wanted if what you wanted was damage.
The agents knew this at the level of naming. They named the missing fields first. Agent A: no error, files, or duration fields. Agent B: no errorCount or filesModified. Then both wrote "Ranking by messageCount only." The word "only" is doing the work. It is not a claim that messageCount is the right metric. It is a claim that it is the remaining metric. Remaining is not the same as requested.
This is how a schema picks a metric without anyone writing a bug. The record has one sortable integer. The task is "rank." The model completes the task. Completing the task on the wrong quantity is still a completion. The parent session, looking at tool results, sees success. The ranking is ordered. The top of the list is the chatty session. The destructive session is somewhere down the page because it did not talk as much.
I do not have the ranked rows. I am not going to invent a session that was chatty, or a session that was destructive, and put numbers on them. The inversion is a property of the metric, not a property of a table I have not seen. Conversation length outranks file churn when file churn is not a column. That is all the quotes support.
Convergence is the diagnostic
One agent doing this is an agent bug you would debug. You would open the prompt. You would check the tool result. You would ask whether Opus-5 has a habit of filling in a ranking when the fields are gone. You would write a note on that agent.
Two independent agents doing it identically is the data model telling you what it does not carry.
The independence is in the parent sessions. Agent A lives under 81da3b23-0992-4c8c-83bc-dfd20d34c9e9. Agent B lives under 10f79aea-ca48-4d4a-8ccb-dc9e505c4fda. Same project tree: -Users-nick-dev-withagents-forge-apps-dashboard. Same model: claude-opus-5. About twenty hours apart: 2026-08-07 17:49, then 2026-08-08 14:05. They are not two turns of the same conversation. They are not a retry. They are two subagents, spawned from two parents, looking at a record that does not have the fields, and both degrading to messageCount.
The wording is not a copy. A's first sentence is "Schema has no error/files/duration fields." B's first sentence is "No errorCount or filesModified fields exist." Different surface. Same diagnosis. Same next sentence. That is the tell. If they had pasted each other, the first sentence would match. It does not. The constraint is upstream of the prose. The schema has one ranking key. Two runs of the same model, given that schema, produce the same key.
Convergent degradation is a schema smell. You do not fix it by telling the agent to try harder. You do not fix it by swapping the model. The 321 Agent spawn calls in this window are the scale of the surface. Two of them, in this tree, on this record, named the hole the same way. I am not going to count how many of the 321 did something similar. The pack gives 321 as the window total, and these two transcripts as the pair. The pair is the evidence. The 321 is the denominator that says Agent spawns were common, not that every spawn did this.
Counts in this series are deduped by unique tool_use_id for tool results, or by message id for text blocks. A raw byte-level regex overcounts because transcripts replay the same event across lines. 321 is the deduped number. I do not have a raw occurrence count for Agent spawns in the pack, so I will not invent one. The method is the same method as the rest of the 30-day window: unique id, not raw bytes.
When two independent runs degrade identically, the constraint lives in the data model, not the prompt. Nobody wrote a bug in Agent A. Nobody wrote a bug in Agent B. The schema chose the metric. The agents reported the choice in plain text and then obeyed it.
What the sessions establish, and where they stop
I want the limit said in the same register as the finding.
The sessions establish the model, the two parent ids, the project tree, the two file paths, the two line numbers, the two mtimes, the two verbatim sentences, and the fact that neither agent raised an error and both returned a ranking. They establish that the fallback field was messageCount. They establish that Agent A named error, files, and duration as missing, and that Agent B named errorCount and filesModified as missing.
The sessions do not establish the parent prompts. They do not establish the schema file. They do not establish a list of ranked rows. They do not establish what the ranking was ultimately used for. I am not going to invent a consumer. A ranking that exists in a subagent transcript is not the same fact as a ranking that drove a cleanup, a sort in a UI, or a decision to kill a session. Those are later claims. They need later evidence.
The sessions also do not establish that messageCount was the only numeric field in the record, only that it was the field both agents ranked by, and that both described the others as absent. "Only" in their sentences is their claim about the ranking key, not my audit of every column. I will keep their wording and not promote it to a full schema inventory.
What I will keep next to both transcripts: if the fields you need to rank by are not in the record, a ranking is not a success. It is a substitution. One substitution looks like an agent being helpful. Two substitutions, same model, distinct parents, twenty hours apart, same fallback, is the schema speaking. Put errorCount and filesModified and duration on the record, or refuse to rank. Do not let the leftover integer become the metric because it is the leftover integer.
Agent A is agent-a0e551f6f9b771a0f.jsonl:37. Agent B is agent-afa27d2de10946a32.jsonl:31. Same closing sentence on both lines: ranking by messageCount only. That is the whole finding. The rest is why two independent agents saying it is a data-model problem, and why a ranking that arrives without an error is the shape that hides it.
Continue the series
- 61SeriesThe Tool That Was Never There: Two Ways an Agent Misses a Tool, Only One Emits an ErrorSixteen unavailable-tool events in 30 days, every one a structured tool error an orchestrator can catch. Then a separate turn that answered in prose and produced no tool event at all, which needs a different check.
- 63SeriesRead Exists But Is Not Enabled: The Difference Between Absent and WithheldA tool that does not exist and a tool that exists but is switched off produce different error text, and only one of them is a configuration problem you can fix.
- 60SeriesThe Vacuous Pass: Three of Four Green Checks Proved NothingThe harness was worse than the note claimed. Three of the four passing checks were vacuous — they could not fail. A check that cannot fail is a caption, not a gate.
- 64SeriesThe Keyboard Trap Video.js Hid: A Control Bar You Cannot Tab ToWCAG 2.1.1 and 2.4.3 both fail when a player hides its own control bar from the keyboard. The fix was three lines of CSS and one line of reasoning.