Skip to content

result.json schema bloat: top-level/agent_result duplication and started_at/finished_at not ISO 8601 #528

Description

@bingran-you

Summary

Two related schema-hygiene issues in result.json that compound:

A. Field duplication between top-level and agent_result

result.json writes three fields twice — once at top level and once inside the nested agent_result block:

{
  "n_tool_calls": 9,                  
  "n_skill_invocations": 0,           ← duplicated
  "n_prompts": 1,                     
  "agent_result": {
    "n_tool_calls": 9,                ← duplicated
    "n_skill_invocations": 0,         ← duplicated
    "n_prompts": 1                    ← duplicated
  }
}

Source: src/benchflow/rollout.py:514-520. Consumers must pick one location; whichever they pick goes stale on the next refactor.

B. started_at / finished_at are not ISO 8601

{
  "started_at": "2026-05-24 21:48:26.264901",      ← str(datetime), space sep, no TZ
  "finished_at": "2026-05-24 21:50:04.087940",     ← same
  "idle_timeout_info": {
    "last_activity_at": "2026-05-25T04:51:45.254841+00:00"   ← ISO 8601 + TZ
  }
}

result.json mixes formats within the same blob. The top-level fields come from rollout.py:540-541 (str(result.started_at)) but rewards.jsonl (rollout.py:262, 282) uses .isoformat() — same project, two parse paths.

Repro

J=$(ls -d /tmp/v05-jobs/test-include/20*/weighted-gdp-calc__*/ | head -1)

# A: duplication
jq '{
  top_calls: .n_tool_calls,
  nested_calls: .agent_result.n_tool_calls,
  top_prompts: .n_prompts,
  nested_prompts: .agent_result.n_prompts
}' "$J/result.json"

# B: timestamp drift
jq -r '.started_at, .finished_at' "$J/result.json"          # space-separated
jq -r '.ts' "$J/rewards.jsonl"                              # ISO 8601
jq -r '.idle_timeout_info.last_activity_at' "$J/result.json" # ISO 8601 + TZ

Severity

P2.

  • Duplication is bloat + latent staleness risk; not a current bug, but a refactor footgun.
  • Timestamp drift forces every consumer (dashboard, check_results, downstream analysis) to branch on format. Already burned #491 (dashboard advisory drift) territory.

Proposed fix

A

Pick one canonical location. The flat top-level fields are likely the older shape; agent_result is the typed-model form. Either:

  • Keep agent_result and remove the top-level duplicates (preferred — agent_result is the typed shape that downstream consumers should use).
  • Or keep flat top-level and remove from agent_result.

Either way, this is a one-breaking-change bullet.

B

Replace str(result.started_at) with result.started_at.isoformat() (TZ-aware datetime needs astimezone(UTC).isoformat() if it isn't already). Audit rollout.py for other str(some_datetime) calls — a quick grep:

grep -n "str(.*started_at\|str(.*finished_at\|str(.*at\b" src/benchflow/rollout.py

Add a unit test that asserts every timestamp emitted by rollout.py parses with datetime.fromisoformat() and is TZ-aware.

Found via

v0.5 e2e validation §2 (threejs-to-obj) and §3 (data-to-d3) at 5a7a326.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Anti-pattern / type safety / docs precision / minor schema drift / non-deterministic but contained.area:rolloutIssue / PR lives primarily in the "rollout" subsystem.enhancementNew feature or requestreviewingFix PR open and awaiting reviewstatus:in-progressHas assignee or linked draft PR.

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    Status
    In Progress

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions