Skip to content

DRC-3025: stamp catalog float/decimal types so decimals compare exactly#1466

Draft
danyelf wants to merge 1 commit into
mainfrom
feature/drc-3025-serialization
Draft

DRC-3025: stamp catalog float/decimal types so decimals compare exactly#1466
danyelf wants to merge 1 commit into
mainfrom
feature/drc-3025-serialization

Conversation

@danyelf

@danyelf danyelf commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

What & why

Fixes DRC-3025 — numeric/decimal values arriving as untyped strings, so decimals were compared as text and flagged as changed on meaningless float noise.

** Still TODO ** could use careful review, and making sure this is ACTUALLY the underlying problem. (We spent a long time on numerical comparison before realizing that this was a string issue.)

Approach: the backend stamps each column's comparison type from catalog.json onto the diff payload; the frontend then routes all cell-compare sites through a single isCellChanged(…, colType) so that DOUBLE/float columns tolerate floating-point noise while DECIMAL stays exact.

Changes

  • Backend — type stamping in recce/adapter/dbt_adapter/__init__.py, recce/tasks/dataframe.py, profile.py, query.py, valuediff.py; new base.ts type field.
  • Frontend — centralized change detection in js/packages/ui/src/utils/dataGrid/ (gridUtils.ts, rowBuilders.ts, toDiffColumn.tsx) and the dataGrid header/render-cell components.
  • Teststests/tasks/test_drc3025_serialization.py (backend), plus frontend gridUtils/rowBuilders unit tests.

Status / notes

  • Opening as draft — this is the validated serialization fix from the recce-fixes workflow (validation passed; aggressive-self-review gate not yet run).
  • Supersedes two earlier closed-unmerged PRsDRC-3025 Float-Precision Rework #1457 and Float-precision-aware cell change detection in the data-diff grid (DRC-3025) #1458 — which were the abandoned float-precision approach on the explore/drc-3025-float-precision branch. Those are dead ends; this branch is the live fix.
  • Verification probe scripts referenced in validation are not committed here; frontend needs pnpm run build before backend test_server.py SPA-route tests pass in a fresh checkout.

🤖 Generated with Claude Code

…tly (DRC-3025)

Numeric values reach the frontend as untyped JSON strings (dbt's agate flattens
DECIMAL and DOUBLE alike to Decimal -> string), so the grid compared them with
bare string-inequality: genuine DOUBLE/aggregate float noise ("0.30000000000000004"
vs "0.3") read as a phantom "modified".

Backend: add an approximate-float column type (DataFrameColumnType.FLOAT, wire
label "float", distinct from exact NUMBER) and stamp each result column's true
comparison type from the catalog -- the offline artifact recce already loads for
lineage. DbtAdapter.catalog_column_types() resolves a model's column DB types;
DataFrameColumnType.from_db_type() maps DECIMAL/NUMERIC -> NUMBER (exact),
DOUBLE/FLOAT/REAL -> FLOAT (approximate), INT* -> INTEGER. value_diff (detail
rows) and query_diff (current_model) stamp model columns; profile stamps its
computed avg/median/proportions FLOAT by construction. Unmatched ad-hoc/expression
columns and catalog-absent cases keep the from_agate type -> exact (safe fallback).
A DECIMAL data column maps to NUMBER, never FLOAT, so a 1-cent change is never
float-collapsed (the cycle-4 guard, by construction). Values stay exact strings;
only the column-type label changes.

Frontend: isCellChanged(base, current, colType) dispatches on the stamped type --
FLOAT parses the numeric strings and applies a magnitude-relative epsilon (with
deep traversal for floats nested in JSON/ARRAY/STRUCT); everything else is exact
deep-equal. All five bare _.isEqual cell-change sites (determineRowStatus,
getCellClass, createCellClassBase/Current, detectModifications) route through it.
FLOAT renders like NUMBER.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Danyel Fisher <danyel@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant