Skip to content

Skip untimed trace records in the OTLP export instead of throwing - #2444

Closed
HugoXK wants to merge 1 commit into
ThinkFlowLab:delivery/ai-centric-development-servicefrom
HugoXK:delivery2/timeline-export-untimed-records
Closed

HugoXK wants to merge 1 commit into
ThinkFlowLab:delivery/ai-centric-development-servicefrom
HugoXK:delivery2/timeline-export-untimed-records

Conversation

@HugoXK

@HugoXK HugoXK commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor

Written-by: Delivery-2

Fixes #2442

Owner: Delivery-2
Tip SHA: 108ddf810f35190feda2b770188d6acada1f524a
Branch: delivery2/timeline-export-untimed-records

What changes

spansFrom (plugins/timeline/src/otel.js) now skips a record whose t is not a finite number, the rule fold in plugins/timeline/src/window.js:63 already keeps for the same trace file. The skip lives in the one loop that indexes ts/te/ks/ke, next to the guard the message records already had, so a turn or tool span is built only from records that carry a usable time.

Why

A trace segment outlives the version that wrote it. Trace.records() (plugins/timeline/src/store.js:173) keeps every record whose t cannot be proved older than the retention window — !(record.t < floor) is true for a missing or non-numeric t — and timeline/export feeds those records straight into spansFrom (plugins/timeline/src/timeline.js:56). nanos then did BigInt(Math.round(undefined)), so one stale record threw RangeError: The number NaN cannot be converted to a BigInt because it is not an integer out of the endpoint and the whole export failed, including the complete turns beside it. The panel view of the same records never had that failure because window.js checks Number.isFinite(record.t) first.

Tests

plugins/timeline/test/otel-untimed-records.test.js, red first on the base 5e71a07e before the one-line guard was added:

  • not ok 1 - a turn or tool record with no usable time is skipped, never converted to a span — error: 'The number NaN cannot be converted to a BigInt because it is not an integer'
  • not ok 2 - timeline/export still answers OTLP JSON when the trace holds an untimed record — same error, raised out of timeline.exportWindow() over a trace holding one untimed turn and one complete turn
  • base: # tests 2 / # pass 0 / # fail 2
  • tip: # tests 2 / # pass 2 / # fail 0

Full timeline suite at the tip: # tests 137 / # pass 137 / # fail 0 (base 135; this branch adds 2).

Gates at the tip

  • plugins/timeline suite: 137/137 pass, 0 fail (command: cd plugins/timeline && TZ=UTC node --import ./test/resolve.mjs --test "test/*.test.js")
  • core lint with ARCH_DOCS_BASE=upstream/delivery/ai-centric-development-service: Found 105 warnings and 0 errors. + arch-docs: OK (3 changed file(s))
  • plugin lint (node scripts/lint-plugins.mjs, npm_config_cache=$PWD/.work/npm-cache): social 36, timeline 9, tree 2, workflow 16 warnings, 0 errors; every pack-import ran
  • node core/scripts/build-client.mjs --check: exit 0
  • node scripts/ds-bot-patches.mjs check: ok ds-bot/ = Fei2411/DeepSeek-Bot@2b10c70, ok 10 patches apply cleanly in order, ok core/ equals ds-bot/ + patches/ds-bot/
  • node .github/scripts/changelog.mjs check: changelog: 80 fragment(s) in changelog.d/ are well formed

Not run: node scripts/build-workbench.mjs --check fails on this box with ERR_MODULE_NOT_FOUND: Cannot find package 'react' (a box dependency, unrelated to this branch), and npm run verify stops at core lint's arch-docs step because origin/main does not exist in this clone, which is why each gate above was run on its own.

Docs-not-needed: the OTLP mapping gains the input guard its sibling reader already has; no owned surface or contract changes.

changelog.d/2442-timeline-export-untimed-records.fixed.md

Files

  • plugins/timeline/src/otel.js (+6 −1)
  • plugins/timeline/test/otel-untimed-records.test.js (+48)
  • changelog.d/2442-timeline-export-untimed-records.fixed.md (+1)

Checkpoint

{
"pr": 2444, "claim": "Delivery-2", "issue": 2442,
"summary": "The OTLP mapping now skips a trace record whose t is not a finite number, the rule the timeline window already keeps for the same file. Without it nanos built BigInt(NaN) and one stale or hand-edited record threw a RangeError out of timeline/export, losing every complete turn beside it. The guard sits in the loop that indexes turn and tool records, next to the one the message records already had.",
"files": ["plugins/timeline/src/otel.js", "plugins/timeline/test/otel-untimed-records.test.js", "changelog.d/2442-timeline-export-untimed-records.fixed.md"],
"checks": { "ran": "cd plugins/timeline && TZ=UTC node --import ./test/resolve.mjs --test "test/*.test.js"; node scripts/lint-plugins.mjs; node core/scripts/build-client.mjs --check; node scripts/ds-bot-patches.mjs check; node .github/scripts/changelog.mjs check", "result": "green", "at": "108ddf810f35190feda2b770188d6acada1f524a" },
"next": "none — ready for review"
}

A trace segment outlives the version that wrote it: the store keeps a record
whose t cannot be proved older than the retention window, and window.js skips
it with !Number.isFinite(record.t). spansFrom did not, so one such record made
nanos throw BigInt(NaN) and the whole timeline/export failed.

Docs-not-needed: the OTLP mapping gains the input guard its sibling reader
already has; no owned surface or contract changes.
@github-actions github-actions Bot added the risk:T2 Risk tier T2 (host/plugin code or an unnamed path), set by the controller from the diff label Nov 4, 2026
@HugoXK

HugoXK commented Nov 5, 2026

Copy link
Copy Markdown
Contributor Author

Written-by: Delivery-2

@Birfy review request for this exact tip: 108ddf810f (base delivery/ai-centric-development-service, merge base 5e71a07e; non-draft, maintainer_can_modify: true).

Red-first on a clean base plus the gates are in the PR body; enqueue-guard is red only because no Verifier report names this tip yet.

Please review 108ddf810f and post Verdict: PASS (or the changes you want). No new tip will be pushed for CI noise: the base head moved to 5ba3c0bb and this branch is not rebased, per instruction.

@HugoXK

HugoXK commented Nov 5, 2026

Copy link
Copy Markdown
Contributor Author

Closing: our account has no write access to ThinkFlowLab/FlyBot, so it cannot merge into delivery/ai-centric-development-service; the fix is complete and verified at 108ddf810f35190feda2b770188d6acada1f524a, and we will re-open it against main or this branch the moment someone with merge rights wants it.

Owner: Delivery-2
Written-by: Delivery-2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk:T2 Risk tier T2 (host/plugin code or an unnamed path), set by the controller from the diff

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant