Skip to content

feat(agents): read JSON-stat 2.0 from statistics office APIs - #12173

Merged
MarkusNeusinger merged 3 commits into
mainfrom
feat/parser-json-stat
Oct 14, 2026
Merged

MarkusNeusinger merged 3 commits into
mainfrom
feat/parser-json-stat

Conversation

@MarkusNeusinger

Copy link
Copy Markdown
Owner

Summary

  • JSON-stat 2.0 from a statistics office's API now parses. The owner's test of 2026-10-14 used the Swiss Federal Statistical Office (BFS) PxWeb API, which answers json-stat2, and the parser refused it as unparseable. Eurostat, Statistik Austria, Statistics Norway and others use the same format. The parser reads it deterministically (no model) into one flat long table:
    • one column per dimension with more than one category, named by the dimension label, with category labels as cells;
    • a value column;
    • the rows in the dataset's own row-major order.
  • Single-category dimensions become notes. They leave the columns (with one warning) and become <label>: <category> notes in context_lines, after the dataset's label, source and note. That way they pass the paste screen (pre-filter + scope judge, feat(agents): keep the notes pasted around a table for the assistant #12168) before a model reads them.
  • Strict validation before a row is built:
    • id and size must match, and the size product must equal the number of values.
    • Category indexes may be an array or an object; a sparse value object is supported.
    • Missing values stay empty, and status symbols are ignored with one warning.
    • MAX_ROWS and MAX_COLUMNS apply.
    • Every inconsistency is unparseable with a message that names no data.
  • Formats. A JSON-stat 1.x bundle with one dataset is read. Several datasets or a 2.0 collection are refused with a clear message. The new source_format is json_stat.

Measurement

The real BFS sample (births and deaths 2024 by canton, 2 KB) becomes 52 rows of Kanton, Demografische Komponente and value. The notes name the year, the nationality total, the sex total and the source.

Plan

N/A

Test plan

  • 14 new test functions in TestJsonStat (23 cases): the trimmed BFS sample, sparse values, index arrays, missing labels, constant dimensions, duplicate labels, a 1.x bundle, 10 inconsistent documents, row caps, unchanged non-JSON-stat shapes, the depth rule, and a loader round trip.
  • pytest tests/unit tests/integration: 10,169 passed. ruff, ruff format, mypy and the changelog check pass.
  • After merge: paste the BFS JSON-stat answer into the live chat (owner's test round).

A JSON-stat 2.0 dataset straight from a statistics office API (BFS PxWeb,
Eurostat, Statistik Austria, Statistics Norway) was refused as
`unparseable`. The parser now detects it (or a JSON-stat 1.x bundle of one
dataset), checks id/size/dimension/value strictly, and flattens it into a
long table: one column per dimension with more than one category, named by
its label and holding the category labels, then `value`, row-major over
`id`. Sparse `value` objects and index arrays are supported; missing values
stay empty; status symbols are ignored with one warning.

One-category dimensions, the dataset's label, source and notes go to
`context_lines`, so the route's pre-filter and scope judge screen them
before the model reads them; the warning only counts the left-out
dimensions. New source format `json_stat`. The 50-level bracket count is
unchanged and applies to JSON-stat too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GdMSqLR5ww4ji74EUSmk9M
Copilot AI balanced review requested due to automatic review settings October 14, 2026 13:23
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GdMSqLR5ww4ji74EUSmk9M
@codecov

codecov Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 91.54930% with 12 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
agents/anyplot/data/parse.py 91.48% 12 Missing ⚠️

📢 Thoughts on this report? Let us know!

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Valid category identifiers can be erased, and a conflicting dimension name can rename or misbind the measure column.

5 open findings
What changed in this PR

Adds deterministic JSON-stat ingestion for statistics-office datasets.

Changes:

  • Flattens JSON-stat datasets into long tables.
  • Preserves metadata and constant dimensions as screened notes.
  • Adds validation, tests, documentation, and changelog coverage.
File Description
agents/​anyplot/​data/​parse.py Implements JSON-stat parsing and validation.
agents/​anyplot/​schemas.py Adds the json_stat source format.
tests/​unit/​agents/​data/​test_parse.py Tests parsing, validation, limits, and round trips.
docs/​reference/​api.md Documents API support.
docs/​concepts/​agent-network.md Documents parser behavior.
changelog.d/​parser-json-stat.md Records the feature.

🧠 Review effort: Balanced


💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread agents/anyplot/data/parse.py Resolved
Comment thread agents/anyplot/data/parse.py Resolved
Comment thread agents/anyplot/data/parse.py Resolved
Comment thread changelog.d/parser-json-stat.md Resolved
Comment thread docs/reference/api.md Resolved
…e measure

Review round 1 on the JSON-stat parser:

- Every dimension column is key-like text, cleaned like the json_pairs
  category (no missing-value mapping, no typing): `NA` (Namibia) and year
  codes stay text; only `value` is typed.
- A dimension labelled `value` in any case is renamed `<label> (dimension)`
  with a warning, so the measure keeps `value` and its default binding.
- Shared category labels are detected in the cleaned NFC form the output
  uses, so `Other` and `Other` behind a zero-width space get their codes.
- The changelog fragment names what the notes carry and what they do not.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GdMSqLR5ww4ji74EUSmk9M

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Empty valid category labels can erase category identity instead of falling back to their codes.

0 open findings

5 resolved since last review
Previously missed (1)

In code that hasn't changed since last review

Medium severity Fall back to category code for empty JSON-stat labels

agents/​anyplot/​data/​parse.py:995

JSON-stat 2.0 permits an empty string as a category label. This branch treats any non-None label as usable, so an empty or invisible-only label becomes ""; a singleton then produces a blank constant note, and a multi-category dimension can produce a missing category cell instead of falling back to its code. Canonicalize the label first and use the code when the result is empty so category identity is preserved.

🧠 Review effort: Balanced

@MarkusNeusinger
MarkusNeusinger merged commit c0e538d into main Oct 14, 2026
16 checks passed
@MarkusNeusinger
MarkusNeusinger deleted the feat/parser-json-stat branch October 14, 2026 14:11
MarkusNeusinger added a commit that referenced this pull request Oct 14, 2026
Resolves the dataset-route row of docs/reference/api.md: main's JSON-stat
passage (#12173) and this branch's 422 code.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GdMSqLR5ww4ji74EUSmk9M
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.

2 participants