Skip to content

v2: spec batch 2 — strict input JSON, the positional export with mixed-body decline, column_defaults, error reasons, known-crash list (ABI v2 d5323993) - #655

Merged
EricAndrechek merged 32 commits into
v2from
v2-sb2-int
Oct 21, 2026

Conversation

@EricAndrechek

Copy link
Copy Markdown
Member

What spec batch 2 changes (ABI v2 dev)

  • Input JSON is strict everywhere; the library refuses an unknown key.
  • The export stays JSONCompactEachRow with one export_columns list. A body that mixes deferred and server-filled defaults declines with defer-defaults-mixed-body, only when an export is asked for.
  • column_defaults: where the server would fill a column from its DEFAULT, the caller's value is used.
  • records, graphite_rollup, identity and session are absent.
  • Rule r8 documents the known-crash list (known-crash-declined at create).
  • Errors carry a reason (chs_error_reason, errors.fields in sdk.json); documents carry reason, refused_at, refused_row, verdict_reason; a value that is not UTF-8 is {"b64": ...}; options documents (insert_options, filter_options, schema_options) on the calls that take them.

This PR integrates the four bindings that implement it (Go, Python, TypeScript, Rust) onto the spec batch 2 base, merges v2 (including build-level revocation), and adds the generator, parity-tool and doc follow-ups the ports found.

Fingerprint proof (measured, on the head)

  • gen.py --write (v1 and --major 2): no diff.
  • gen.py --check and gen.py --major 2 --check: exit 0.
  • gen.py --major 2 --fingerprint: sha256:d53239933966e15a3c363e631a94fbba1231d84c4300337115d3ae5377bb41c2, unchanged from the spec batch 2 base. spec/abi-v2/ and include/v2/chtypes.h are not touched by this PR beyond what v2 itself brought.

Beyond the ports

  • CODE_DECLINED. docs/reference/bindings-v1.md promises a declined-code constant (CHS_CODE_DECLINED, -2) in every binding, but only Go's emitter generated one. The generator now emits CODE_DECLINED = -2 into Python's generated vocabulary (exported from chtypes), CODE_DECLINED into TypeScript's vocab.gen.ts (exported from the package), and pub const CODE_DECLINED: i32 = -2 for Rust at the crate root (chtypes::CODE_DECLINED; not code::DECLINED, because code is the generated fetch-code table, and the doc's Rust cell now says so). The TS parity allow entry that carried the gap is removed. This is a maintainer-visible naming call.
  • scripts/parity-surface.py now reads the description of the major the bindings speak (spec/binding-majors.json, v1 where absent) and refuses mixed majors; its selftest covers both. Before, every v2 vocabulary growth read as drift (Source: 13 members vs 11).
  • docs/guides/settings.md describes the {"b64": ...} form and which bindings can send it. Rust cannot: it takes String.

Per-binding surface

Concern Go Python TypeScript Rust
insertable columns WithInsertableColumns insertable_columns= insertableColumns insertable_columns
column defaults WithColumnDefaults([]ColumnDefault) column_defaults= (ColumnDefault) columnDefaults column_defaults
verdict basis WithVerdictBasis verdict_basis= verdictBasis verdict_basis
defer defaults WithDeferDefaults defer_defaults= deferDefaults defer_defaults
raw option pass-through WithInsertOption / WithFilterOption / WithSchemaOption *_options_extra= *OptionsExtra *_options_extra (key, JSON text)
param encoding WithParamEncoding param_encoding= paramEncoding param_encoding
posture WithPosture posture= posture posture
error reason CallError.Reason CallError.reason CallError.reason CallError::reason
spans []*Span, nil = not exported tuple[Span or None] (Span or null)[] nullable spans
non-UTF-8 value any string str with surrogateescape Uint8Array cannot (String)
CODE_DECLINED CodeDeclined (existing) CODE_DECLINED (new) CODE_DECLINED (new) chtypes::CODE_DECLINED (new)

Departures from Go: Rows.Spans is []*Span; AtMergeEntry.Row is PartRow in every binding; row-level unsupported_settings is removed everywhere; the row, batch and filter results gain reason, refused_at, refused_row; columns gain default_support, default_support_reason, reads; a schema description gains posture; a server profile's b64 settings decode to their bytes (Rust: RawText). The full naming table is in docs/reference/bindings-v1.md and each binding's CHANGELOG.

Expected red

The required examples job fails every tour at "CLI fetch of line 26.9 failed (ABI v2)": the fingerprint moved to d5323993, and no published build carries it yet. It clears once the artifact producer publishes a dev build at this fingerprint.

Supersedes

#650 (Go), #652 (Rust), #653 (TypeScript), #654 (Python). They are CI vehicles and are closed after this merges.

🤖 Generated with Claude Code

EricAndrechek and others added 30 commits October 19, 2026 15:42
The maintainers' decided cell for the second v2 spec batch, with body_read
added to every refused_at enum (the vocabulary already had it):
- input JSON is strict everywhere;
- the export stays JSONCompactEachRow with one export_columns list, and a
  body mixing deferred and server-filled defaults declines with
  defer-defaults-mixed-body;
- column_defaults: where the server would fill a column from its DEFAULT,
  the caller's value is used;
- records, graphite_rollup, identity and session are absent;
- r8 documents the known-crash list (known-crash-declined at create);
- errors carry a reason (chs_error_reason; sdk.json errors.fields).

spec/abi-v2/abi.json, its schema, docs.md, sdk.json and the generator are
the inputs; every generated file is the generator's output:
gen.py --write leaves no diff, --check passes for both majors, and
gen.py --major 2 --fingerprint prints
sha256:d53239933966e15a3c363e631a94fbba1231d84c4300337115d3ae5377bb41c2.

The bindings' hand-written surface for the new members follows in this
branch before it lands.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… call arguments

WithInsertableColumns, WithColumnDefaults, WithVerdictBasis, WithDeferDefaults and WithInsertOption
build insert_options for Row, Rows, ParseBlock and Filter.Rows; WithParamEncoding and WithFilterOption
build filter_options; WithPosture and WithSchemaOption build schema_options. WithColumns now applies
to Filter.Rows. A settings, query-parameter, defaults or server-settings value that is not UTF-8 is
the {"b64": ...} object form instead of a refusal.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…mbers

RowResult, BatchResult, FilterResult and FilterRowError carry the reason, refused_at and refused_row
members; the batch carries ExportColumns, ExportDeclinedReason and a Spans slice aligned with Rows (a nil
entry for a row not exported); AtMergeEntry.Row is PartRow; the row-level UnsupportedSettings is removed;
Column carries DefaultSupport, DefaultSupportReason and Reads; SchemaDescription carries Posture; a
server settings value in the b64 form decodes to its bytes.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…de member

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…he new names

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Go's CallError, Python's ErrorInfo and the call error classes, and Rust's
RawCallError read chs_error_reason when the description declares it.
Output for ABI v1 is unchanged; the v2 fingerprint is unchanged.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…lter_eval_body

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…al and export members, part_row)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…nd decline members, error reason, schema description)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…, error reason)

Mirrors the Go naming table: insert/filter/schema options, the {"b64": ...}
form for a non-UTF-8 settings value, reason/refusedAt/refusedRow/verdictReason,
export columns and decline reason, nullable row spans, partRow, schema
posture and default support, CallError.reason read by hand in abi2/raw.ts.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…n test

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…-level unsupportedSettings, reason)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…upported_settings)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…w key

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
bindings-v1.md promised a declined-code constant in every binding; only Go's
emitter generated one. Python: CODE_DECLINED in the generated vocab, exported
from chtypes. TypeScript: CODE_DECLINED in vocab.gen.ts, exported. Rust:
chtypes::CODE_DECLINED (crate root; the code module is the fetch-code table),
and the doc row says so. The TS parity allow entry that carried the gap is gone.
ABI v2 fingerprint unchanged.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
DESCRIPTION was hard-coded to spec/abi-v1/abi.json, so every v2 vocabulary
growth read as drift (Source: 13 members vs 11). It now follows
spec/binding-majors.json (v1 where absent) and refuses mixed majors; selftest
covers all three.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…all four bindings

Unit tests assert the exact insert_options JSON (UTF-8, value_b64/name_b64,
empty value, order) and the default_override decode; the batches guide gains
a usage section; CHANGELOG bullets. No change under spec/abi-v2 or include/v2.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…el unsupported settings, nullable spans)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@EricAndrechek
EricAndrechek merged commit 6e731ff into v2 Oct 21, 2026
53 of 54 checks passed
@EricAndrechek
EricAndrechek deleted the v2-sb2-int branch October 21, 2026 04:33
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