Repository navigation
fix(agents): keep pasted data exact or warn about every change - #12196
Merged
Merged
Conversation
Owner rule of 2026-10-15: precision is never lost silently. - loader: read data.csv with float_precision="round_trip" (pandas 3's default reader misread ~23 % of 17-digit floats by one ulp) - parse: count numbers stored rounded (more digits than a float64), keep JSON/literal float texts, whole numbers past int64 stay text, warn on NFC, trimmed text cells and missing tokens in text columns, exact integer min/max in the profile - prepare: exact whole numbers in set_type number, aggregate sum (no Int64 wraparound), cumsum; change lines count rounded values; keep sub-seconds and offsets; year-first ISO not read day-first; mixed UTC offsets refused instead of crashing Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GdMSqLR5ww4ji74EUSmk9M
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GdMSqLR5ww4ji74EUSmk9M
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
Parsing performance, incorrect running-total grouping, and incomplete loss warnings remain unresolved.
5 open findings
Avoid quadratic AST source scanning during paste parsing · New Preserve numeric grouping semantics for signed zero · New Preserve digit fidelity when parsing underscored floats · New Preserve leading-space evidence in CSV text columns · New Ensure rounding notices survive truncated operation messages · New
What changed in this PR
Improves data fidelity across agent-chat parsing, preparation, and exported plots by preserving precision or reporting changes.
Changes:
- Adds exact float loading and counted normalization warnings.
- Preserves integer calculations and timestamp precision.
- Expands regression coverage and documents fidelity guarantees.
| File | Description |
|---|---|
tests/unit/agents/evals/test_stress.py |
Checks round-trip loader generation. |
tests/unit/agents/data/test_prepare.py |
Tests operation precision and timestamps. |
tests/unit/agents/data/test_parse.py |
Tests numeric fidelity and normalization warnings. |
tests/unit/agents/code/test_loader.py |
Tests exact float read-back. |
docs/concepts/agent-network.md |
Documents fidelity behavior. |
changelog.d/agent-data-fidelity.md |
Records user-facing fixes. |
agents/evals/stress.py |
Aligns evaluation loading with production. |
agents/anyplot/schemas.py |
Allows exact integer profile bounds. |
agents/anyplot/data/prepare.py |
Preserves calculation precision and reports rounding. |
agents/anyplot/data/parse.py |
Retains numeric source text and counts changes. |
agents/anyplot/code/loader.py |
Enables round-trip float parsing. |
🧠 Review effort: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
- literal float texts sliced from lines split once (get_source_segment per float was quadratic); digit separators dropped from the kept text so every digit reaches the rounding count - exact cumsum groups native key values (-0.0 with 0.0, as pandas) - a rounding notice is never cut by the change-line cap: the descriptive part is shortened instead Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GdMSqLR5ww4ji74EUSmk9M
- set_type datetime chooses day-first per cell, so one cell of another shape no longer turns the year-first ones around - an exponent past the decimal module's range takes the float path instead of raising InvalidOperation Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GdMSqLR5ww4ji74EUSmk9M
Merge #12194 (ISO timestamps with fractions and offsets in parse.py): its _cell_text (value.isoformat()) replaces moment_text; both test classes kept. Owner decisions of 2026-10-15: - one warning counts numbers whose spelling went (trailing zeros, exponent, plus sign), naming their columns - set_type datetime reads different UTC offsets in UTC with a change line naming them, as the parser does; naive beside zoned is refused - the preview keeps whitespace; the data panel draws line breaks as ↵ and space runs as ·, muted and named for screen readers - profile mean/median at six digits (model only) and integers past 2^53 in the browser kept and documented Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GdMSqLR5ww4ji74EUSmk9M
Conflict in docs/concepts/agent-network.md (Parse paragraph): main's text kept, this PR's fidelity, loader and prepare sentences re-applied. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GdMSqLR5ww4ji74EUSmk9M
- conditions on a column with a UTC offset compare moments; a value with the wrong kind of zone is refused instead of crashing with TypeError - conditions on whole-number columns compare exact integers - nanosecond times beside a date outside 1677..2262 stay text with a warning (the loader had turned them text silently) - JSON NaN/Infinity/-Infinity counted as missing - whole numbers past int64 with dot groups stay text with BIG_INTEGERS - results past 2^53 written as floats are counted, also exact ones (2^63); float results count their Int64 inputs past 2^53 - read and loader use date_format="ISO8601" (no inference warning) - set_type datetime wording says year first where it is; missing-token note counts further tokens; preview marks a tab as → Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GdMSqLR5ww4ji74EUSmk9M
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


Summary
This PR audits how faithfully the agent chat keeps pasted data and fixes every silent precision loss it found. It follows the owner rule of 2026-10-15: what the user pastes is what the data holds, or a warning or change line says what changed and how often. Silent precision loss is treated like silent corruption.
Audit
code/loader.py: run-formpd.read_csv(exportedplot.py, sandbox render)float_precision. On pandas 3.0, about 23 % of realistic 17-digit floats were read 1 ulp off, so the plot did not draw the values indata.csv.float_precision="round_trip"whenever a number column exists. Test: 2,000 random floats of every magnitude plus extremes read back bit-exactly.parse.py_as_numbers: CSV number cells0.1234567890123456789,9007199254740993beside decimals, subnormals,1e-400)parse.py_decode_literal: JSON and Python-literal floatsjson.loadsandliteral_evalrounded them before typing, with no warning._SourceFloat), so the same count applies. JSON1e400is now text instead of vanishing as missing.parse.pyintegers past int641.2345678901234568e+22).set_type numbercan still convert it, and its change line counts the rounding.parse.pyprofilemin/maxof integer columnsint(ColumnProfile.min/max: int | float | Cell).parse.pytrailing zeros,+, exponent,-01.50becomes1.5,1e3becomes1000.0,-0becomes0parse.pythousands and decimal-comma normalization,%and currencyparse.pytext cells: surrounding whitespaceparse.pytext cells:None,-,null, …parse.pyNFCparse.pyzero-width and bidi characters, header canonicalization, 200-character cell capparse.pythinning of list fields over 20,000 rowsprepare.pyset_type number9007199254740993became…992), silently.Decimal(Int64). The change line counts rounded cells.prepare.pyaggregate sumof Int642 × 9.2e18gave-1616).prepare.pyderive cumsumof Int64prepare.pyderive sumanddifferencepast int64prepare.pypivot_longerof Int64 beside float64prepare.pyderiveratio,share,percentprepare.py_cell_text: date-timestimespec="seconds"dropped them silently.moment_text: microseconds or nanoseconds when present. The offset is kept.prepare.pyset_type datetimewithout a format2024-06-01T13:00:00Zwas read as 6 January (dayfirst=True).prepare.pyset_type datetimewith mixed UTC offsetsValueError, so the tool crashed.type_mismatchrefusal. The times are not converted.prepare.py_readand_write,render/harness.pyframe_csv_readalready usedround_trip.to_csvwrites repr (verified bit-exact on 20,000 random doubles).parse.pydates,_iso, loaderparse_datesM8[us]on pandas 3.feat/agent-file-drop-binary).DataPanelPreviewTable)…, and whitespace runs are collapsed for display.Owner decisions (2026-10-15), applied
1.50becomes1.5), but one warning now counts the numbers whose trailing zeros, exponent or plus sign went, and names their columns. Spelling the canonical form only adds (2as2.0,.5as0.5,1e-7as1e-07) is not counted.set_type datetime. Times with and without an offset in one column are refused.parse.preview_cell). The data panel draws a line break as↵and each space of a run as·, muted and with screen-reader text. The model-facing sample and top values stay one line.1, alpha.Merge with #12194
origin/main is merged in. #12194's
_cell_text(value.isoformat(), which writes every fraction digit and the offset) replaces this PR'smoment_text, and both test classes are kept. The stress caseduplicate-headersnow expects 4 warnings, including the spelling line; it was regenerated withmake_stress. The parse-only fixture test ignores the spelling line.Frontend
The change is
app/src/sections/agent-chat/previewCell.tsplus its use inDataPanel, with Vitest coverage inpreviewCell.test.tsandDataPanel.test.tsx. App gates on Node 24 pass: lint, Prettier, type-check, 1,114 tests and the build. I did not drive the page in a browser in this session.Test plan
TestFidelityintest_parse.pywith generalized fixtures: random decimals of 1, 7 and 15 digits in CSV, JSON, written JSON and Python literals keep their exact value with no warning; 19-digit decimals plus edge cases are counted exactly; int64 limits are exact and larger integers become text; NFC, whitespace and missing-token warnings; no warning for aligned padding or number columns.TestFidelityintest_prepare.py: 500 random floats of every magnitude plus integers past 2^53 survive operations exactly;set_type, aggregate sum, cumsum and sum overflow, thepivot_longercount, sub-seconds and offsets, the year-first fix and the mixed-offset refusal.test_loader.py: bit-exact read-back of 2,000 random floats plus extremes through the run form.uv run pytest tests/unit -n 8: 11,318 passed.ruff checkandruff format --checkon the repo,mypy api core agentsand the changelog check all pass.app/change, so no frontend gate applies.🤖 Generated with Claude Code
https://claude.ai/code/session_01GdMSqLR5ww4ji74EUSmk9M