Skip to content

v2 lock: stability locked, production channel default, 2.0.0 (DRAFT, held for the maintainer) - #672

Draft
EricAndrechek wants to merge 35 commits into
v2from
v2-lock
Draft

EricAndrechek wants to merge 35 commits into
v2from
v2-lock

Conversation

@EricAndrechek

@EricAndrechek EricAndrechek commented Oct 21, 2026 •

Copy link
Copy Markdown
Member

HELD UNMERGED until the maintainer approves the lock (#596). Do not merge, do not tag.

The v2 lock, as #596 lays it out: ABI v2's description is locked, the production generation-2 fetch channel becomes every binding's default, the four packages say 2.0.0, the docs stop describing a dev pre-release, and each CHANGELOG has one 2.0.0 section.

Identity at this head

before (v2 b7a6c3e3) this PR
CHS_ABI_FINGERPRINT (gen.py --major 2 --fingerprint) sha256:d53239933966e15a3c363e631a94fbba1231d84c4300337115d3ae5377bb41c2 sha256:78518cd5f88205ff4fcdbd94b137566192d7993888a6dc0d65de3357f6044b4e
shasum -a 256 include/v2/chtypes.h 047512a8144bdacafd1c86098bb3229aab6769d5151193956bdd6ff5df6cab36 6070e6229270ce59af779478cf2f4c47f0d5052cbbf632d3a68638fe6264dd7f

The fingerprint moves only with stability. The header's bytes also carry the prose that now says locked (its Stability paragraph), which is outside the fingerprint.

What changed

  1. The lock. spec/abi-v2/abi.json: "stability": "locked", then regenerated with gen.py --major 2 --write. The prose in spec/abi-v2/docs.md and docs/reference/abi-v2.md says locked. The where-settings note marked for removal at the lock is removed.

  2. The production channel is the default in all four bindings: active() falls back to it (Go channel.go, Python _channel.py, TypeScript channel.ts, Rust channel.rs).

    • It fetches from https://registry.wavehouse.dev/chtypes/v2 under the release key, and honors every override and pin.
    • Its cache is ~/.cache/chtypes/v2, or <cache>/v2 under an explicit cache.
    • The dev channel stays, reachable only through each binding's test seams, and the dev-channel tests select it explicitly.
    • The real-CLI tests now prove that a non-test binary speaks production.
    • These follow the production channel, read from spec/fetch-v1/constants.json or scripts/release-channel.sh: the shared cache-roots table, the CLI parity rows, the interop job's system directory, examples/chplay.sh, and release-channel.sh get <NAME>.
  3. 2.0.0 in the eight places the 2.0.0-dev.N bumps changed: the three manifests, Go's bindingVersion, and the four lockfiles.

  4. Docs.

    • The README, the four binding READMEs, docs/install.md, docs/quickstart.md, docs/reference/go.md and docs/guides/artifacts.md now install 2.0.0 the plain way, with Go on the /v2 module path.
    • docs/guides/fetch-v1.md ("Generation 2 after the lock") says the production channel is the default.
    • docs/limitations.md notes that its build ids are v2 development builds.
  5. CHANGELOGs (CHANGELOG: consolidate the dev-era entries into one 2.0.0 section per binding #599). Each binding has one [2.0.0] section relative to 1.1.0, with the same structure in all four:

    • Added.
    • Changed, opening with one migration list from 1.x.
    • Removed.
    • Fixed.

    Pairs that cancel or supersede each other are collapsed. Entries that apply only to the dev channel are named once, in the intro. The 1.x sections are untouched.

CI that is red until the 2.0.0 libraries are published

#596's order applies: the artifact producer builds from this head, then publishes to production chtypes/v2.

  • The examples and interop legs run the real CLIs, and those now fetch from production chtypes/v2. They fail until the 2.0.0 libraries are there.
  • The support-v2 page check runs because this PR touches its generator, whose selftest now expects the production channel. It compares docs/support-v2.md against production, so it stays red until the page is regenerated after the first production publish (uv run scripts/support-v2/gen.py --write, RELEASING.md).

Lock-review text fixes

Prose and data only: spec/abi-v2/abi.json is untouched and the fingerprint is unchanged (sha256:78518cd5…). The header is regenerated because its comments come from docs.md.

  • The decline catalog (spec/abi-v2/declines/declines.json) is re-copied byte for byte from the artifact producer: 55 → 138 entries, no id removed. The README says this file is the published catalog rule r4 freezes, documents the new misuse and export-decline classes, the load_dependence field and the retired form, and pins the new sha256; check-declines.py pins the eight classes.

  • docs.md: the lock in the present tense; CHS_REJECTED no longer listed for chs_schema_describe; exact message text guaranteed only where the description quotes it; column_defaults and defer_defaults implemented and advertised in capabilities.features; the three clock knobs refused (115) by chs_set_defaults and a schema's settings; an EPHEMERAL column in columns read as ephemeral_input; macros validated but not applied (declined); the non-NULL server hedge removed; SHOW CREATE TABLE output measured compiling for 32 of 32 shapes.

  • abi-v2.md: nine rules, r1 to r9.

  • limitations.md: names the 2.0.0 build 20261021.191313; the EPHEMERAL entry corrected; binary parameters fixed in v2 for Go, Python and TypeScript; SHOW CREATE of a Memory table retired as fixed; the 1.0 headings made version-neutral, with their old anchors kept.

  • The four CHANGELOGs, the README and the discovery guide follow the new counts.

  • The reserved macro behaviour is tied to server_profile.macros. A build that applies a server profile's macros advertises server_profile.macros in capabilities.features (rule r9). Only such a build reads present macros as the complete set, with the 139 refusal. Every other build validates macros and declines a macro-reading schema.

  • Stale text outside the spec is updated:

    • the "does not compile on a server yet" and macros-"expand" wording in the Go README, bindings-v1.md, the examples README, the tour comments and the four bindings' doc comments;
    • the 1.0 wording in README.md, python/README.md, docs/reference/python.md and docs/install.md, which now names no version.

Not in this PR

The goldens runners in all four bindings, and the v1-goldens and v1-real workflows, still select the dev channel for a registry run. Moving them to production waits for a production build that carries goldens.

Closes #599. Refs #596, #511

🤖 Generated with Claude Code

EricAndrechek and others added 30 commits October 21, 2026 14:33
spec/abi-v2/abi.json declares `stability` "locked", so the fingerprint
moves one last time (rule r6): sha256:d53239933966... ->
sha256:78518cd5f88205ff4fcdbd94b137566192d7993888a6dc0d65de3357f6044b4e.
Every output is regenerated with gen.py --major 2 --write. The prose
(spec/abi-v2/docs.md, outside the fingerprint) says locked: the title,
the status paragraph and the header preamble's Stability paragraph; the
where-settings dev-only note marked for removal at the lock is removed.

Refs #596, #511

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The same eight places every 2.0.0-dev.N bump changed: the three manifests,
Go's bindingVersion, and the four lockfiles that carry the version
(uv lock in python/ and examples/python/, cargo update -p chtypes in rust/
and examples/rust/).

Refs #596

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
active() falls back to the production generation-2 channel in all four
bindings (Go channel.go, Python _channel.py, TypeScript channel.ts, Rust
channel.rs): https://registry.wavehouse.dev/chtypes/v2, the release key,
every override and pin honored, the v2 cache (docs/guides/fetch-v1.md,
"Generation 2 after the lock"). The dev channel stays, reachable only
through each binding's test seams, and its tests select it explicitly.
The real-CLI tests now prove a non-test binary speaks production.

The shared cache-roots table, the CLI parity rows, the interop system
directory, examples/chplay.sh and release-channel.sh's bare `get` follow
the production channel; the support-v2 generator's selftest expects it.
CLI help, package docs and fetch-v1.md say it is the default.

Refs #596, #511

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The four binding READMEs describe the locked ABI v2 and the production
channel instead of the 2.0.0-dev banner, and install 2.0.0 the plain way.
The Go install, import and `go run` lines use the /v2 module path (the
README badge too). docs/limitations.md says its build ids are v2
development builds, re-checked on the 2.0.0 libraries once published.

Refs #596

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The dev-era Unreleased entries fold into one [2.0.0] section in each
binding, in the same structure: Added, Changed (opening with one
migration list from 1.x), Removed and Fixed. Pairs that cancel or
supersede each other are collapsed (the server-level
filter_declined_settings, row -> part_row, the gate lifted, restored and
lifted again), dev-channel-only entries are named once in the intro, and
the foundations the dev entries never listed (the server profile,
at_merge, CHTYPES_OFFLINE and the cache roots, the r3 unknown members,
the v2 registry and cache) are added. The 1.x sections are unchanged.

Closes #599

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The lock left four checks assuming the description is unstable.

- gen.py --selftest asserted the tree's own header carries an UNSTABLE
  note. It now plants an unstable copy and a locked copy, and checks the
  header and the reference page's stability row in each, so the proof
  holds whichever state the tree is in.
- The r6 fingerprint-refusal tests skipped (Go, Python, TypeScript) or
  failed (Rust) on a locked description, and the ABI conformance census
  requires them to pass. Each binding now proves both sides:
  - this SDK as built is locked, so a library with another fingerprint
    is still refused as CHTYPES_ARTIFACT_INCOMPATIBLE, naming both
    fingerprints, with the loader's own message and never the dev one,
    alone and through a load of the fingerprint-other stub;
  - the dev side, rule r6's exact text, is selected explicitly: a
    stability parameter on the existing mapping (Go
    devFingerprintMessageAt, Rust Refusal::dev_message_at, TypeScript
    incompatibleMessageAt, none public) or, in Python, the generated
    stability patched for one test.

No behavior changes: each refactor passes the generated stability to the
same comparison. No generated file changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- spec/abi-v2/declines/declines.json: re-copied byte for byte from the
  artifact producer, 55 -> 138 entries (no id removed; three misuse ids
  now CHS_INVALID_ARGUMENT, admission-envelope retired). The README
  states that this file is the published catalog rule r4 freezes,
  documents the two new classes (misuse, export-decline), the
  load_dependence field and the retired form, and pins the new sha256.
  check-declines.py pins the eight classes the data now uses.
- docs.md: the lock in the present tense; chs_schema_describe's
  CHS_REJECTED dropped from the history paragraph; exact message text
  guaranteed only where the description quotes it; column_defaults and
  defer_defaults implemented and advertised in capabilities.features;
  the clock knobs refused (115) by chs_set_defaults and a schema's
  settings; an EPHEMERAL column in a columns list read as
  ephemeral_input; macros validated but not applied; the non-NULL
  server hedge removed; SHOW CREATE output measured 32 of 32.
- abi-v2.md: nine rules, r1 to r9 (hand-written intro).
- limitations.md: the 2.0.0 build named; the EPHEMERAL entry corrected;
  binary parameters fixed in v2 for Go, Python and TypeScript; SHOW
  CREATE retired as fixed; the 1.0 headings made version-neutral, old
  anchors kept.
- Four CHANGELOGs, README and the discovery guide follow the counts.

The header is regenerated (its comments come from docs.md); abi.json is
untouched and the fingerprint is unchanged (sha256:78518cd5...).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… stale non-spec text

spec/abi-v2/docs.md: the reserved "a later build that applies macros"
behaviour (present macros as the complete system.macros, the 139
NO_ELEMENTS_IN_CONFIG refusal) is tied to the feature value
server_profile.macros in capabilities.features (rule r9); a build that
does not advertise it validates and declines a macro-reading schema, as
the rule says. :366 and :538 read consistently with that. Regenerated;
abi.json untouched, ABI v2 fingerprint unchanged.

Outside the spec, the text that still said a build does not yet compile
on a server, or that the server's macros "expand", now says the library
compiles on a server and validates macros, applying them only where a
build advertises server_profile.macros: go/README.md, bindings-v1.md,
examples/README.md and the Python/TS tour comments, and the Go, Python,
Rust and TS doc comments. The 1.0 wording in README.md, python/README.md,
docs/reference/python.md and docs/install.md is updated for the current
major, without naming a version.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The artifact producer corrected its catalog: the stack-depth entry no
longer lists chs_schema_describe among its paths, since describe never
refuses (as docs.md and the description's may_return say). The file is
re-copied byte-for-byte (138 entries, sha256 147dff4a...); the README
names the producer commit and the new sha256. abi.json and the header
are untouched; the ABI v2 fingerprint is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
docs.md's Images rule carried "(Pending the confirmation runs with the
time budget at 0, and the remaining arm64 cells at the default budget and
at 0.)". The artifact producer ran them on the 2.0.0 libraries (build
20261021.191313): the budget at 0 on both architectures, and the arm64
cells at the default budget and at 0, four images by 32 threads, each
compared with a single image on a single thread. Every cell agreed, with
no over-accept and no budget decline, so the parenthetical is removed;
the rest of the rule stands. Regenerated; abi.json untouched, ABI v2
fingerprint unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The only conflict was each binding's CHANGELOG: v2 added the lean
default's "Breaking (vs the 2.0.0-dev releases)" bullet under
[Unreleased], which this branch consolidated into one [2.0.0] section.
Resolved by keeping this branch's [2.0.0] section and adding the change
to its "Breaking: migrating from 1.x" list: 1.x and the 2.0.0-dev
releases both defaulted to every document group. abi.json untouched,
ABI v2 fingerprint unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ery Go example) into v2-lock

No conflicts: .github/workflows/ci.yml and examples/go/ingest-demo/main.go
only. abi.json untouched, ABI v2 fingerprint and header unchanged; the Go
examples vet and build against this tree.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
docs.md said a schema's home zone is its server's `timezone`, else the
image zone. A real 26.8 server whose `timezone` and whose profile's
`session_timezone` differ binds a table's zone-less types to the
`session_timezone` (measured by the artifact producer, in both
postures). The home zone is therefore the `session_timezone` in the
server profile's `settings` when set, else the server's `timezone`, else
the image zone, in both postures; the schema's own `session_timezone`
still never binds its types. The 2.0.0 library build does the same.
Regenerated; abi.json untouched, ABI v2 fingerprint unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ichever refusal answers

The batch document's top-level unsupported_settings said only that it is
empty when no setting was declined. A call-level decline of another kind
(an export format the build cannot write, an insert_options member, a
filter zone that is not the batch's, column_defaults on a Native body)
answered it empty on the 2.0.0 candidate build although the call had
declined settings. The rule now says it names them whichever refusal of
the call answers, so it is empty only when the call declines none; the
fixed 2.0.0 build implements it. Prose only: regenerated, the header is
unchanged, abi.json untouched, ABI v2 fingerprint unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…lt names call-level declines too

The batch document's top-level unsupported_settings now reads, as the
lead ruled: it names every setting the call declined, whichever refusal
of the call answers; it is empty only when the call declines none, or
they could not be read (a deep argument that is itself the settings
document). filter_result's unsupported_settings says the same, as the
batch's does: chs_filter_eval_body and chs_filter_eval_block mirror the
batch verdict, a call-level decline included. Prose only: regenerated,
the header is unchanged, abi.json untouched, ABI v2 fingerprint
unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… never the home zone

docs.md said an empty session_timezone "means the server's zone, the
last two". Since a schema's home zone is now the zone its server binds
(the profile's session_timezone when set), "the server's zone" read
ambiguously. A real 26.8 server (26.3 agrees) runs a call naming '' in
its own timezone, never the profile's (measured by the artifact
producer): the body is read and rendered in the server's timezone while
the schema's bound types keep the home zone. The sentence now says so.
Prose only: regenerated, header diff is comment lines only, abi.json
untouched, ABI v2 fingerprint unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The artifact producer's fixed build updates the schema-server-zone
entry: its trigger and description now name the zone a server binds its
types to (the server profile's session_timezone when set, else its
timezone), and the posture-load case of a column type that holds an
AggregateFunction under a server zone other than the image zone. The file
is re-copied byte-for-byte (138 entries, sha256 30537b44...); the README
names the producer commit and the new sha256. abi.json and the header
are untouched; the ABI v2 fingerprint is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ubuntu-26.04's sudo refuses to preserve the whole environment ("preserving
the entire environment is not supported, '-E' is ignored"), so the required
v1-sandbox selftest failed at proof 1c ("environment did not survive the
sandbox"). The caller's variables now travel NUL-separated in a mode-600
mktemp file; inside the namespace, after setpriv drops back to the caller,
env -i rebuilds exactly that environment with PATH and HOME passed
explicitly. The file is removed when the command ends. Proof 1c is unchanged.

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

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

# Conflicts:
#	examples/python/uv.lock
#	examples/rust/Cargo.lock
#	go/CHANGELOG.md
#	go/internal/ocifetch/useragent.go
#	python/CHANGELOG.md
#	python/pyproject.toml
#	python/uv.lock
#	rust/CHANGELOG.md
#	rust/Cargo.lock
#	rust/Cargo.toml
#	ts/CHANGELOG.md
#	ts/package.json
… release-verify check 6

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The catalog is the producer's at 74bba4fb, byte for byte: 159 entries
(was 138) over the lines 26.3, 26.8, 26.9 and 26.10 (26.7 leaves the
supported set). 21 ids are added, none removed or retired.

One entry is now `dormant: …` with an empty `lines` (a reason no pinned
line can emit whose check the library still holds); the checker's line
rule accepts exactly that form, and a planted case proves a dormant
entry that lists lines fails. The README's field table, provenance and
sha256 line follow; the CHANGELOGs' count follows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The five per-line lists, the new 26.10.json and the union are the
producer's at 74bba4fb, byte for byte, from the tags v26.3.60.2-lts,
v26.7.19.5-stable, v26.8.34.13-lts, v26.9.25.15-stable and
v26.10.2.103-stable: 390, 446, 478, 481 and 484 entries, 509 in the
union. documented-pathological.tsv is the producer's at the same commit
(14 rows): the 26.10 cells are added, and the four profile-layer
max_expanded_ast_elements=1 rows, which the producer dropped earlier,
are gone. 26.7.json stays for a line still served but no longer
supported. The checker knows the 26.10 file; the README's provenance
and hashes follow.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ved, unsupported

Whether a line is supported, and the patch a supported line models, are
not in any signed statement, so the generator reads them from a copied
table, scripts/support-v2/lines.json: the producer's per-line state at
74bba4fb. 26.3.60.2, 26.8.34.13, 26.9.25.15 and 26.10.2.103 are
supported; 26.7 is served, unsupported.

The page gains a support table (line, state, patch modeled) and the
sentence "A server on a different patch of the same line can answer
differently; chtypes models the patch named here." A supported line's
verified row on another patch is omitted and named, and so is a
supported line the registry does not publish; a served, unsupported
line keeps its served build's rows under a marked heading; a published
line the table does not name reads `support unknown`. Each rule has a
selftest case, and a malformed lines.json exits 2.

docs/support-v2.md is not regenerated here: the production registry's
tag listing names no line yet, so --write writes nothing (exit 4).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Preamble names, in the producer's own terms: the merge-time TTL
model (`at_merge`) evaluates a TTL expression under the library's
process-wide settings, not the server profile; on 26.3 a lone -0.0 can
be stored as +0.0 by sparse serialization, so a row's stored rendering
can show -0 where the server stores +0 and a filter that reads such a
value answers that row d (float-negative-zero-sparse-default); and on
26.3 the remote form of hasColumnInTable is refused by the screen
alone, not by the context. include/v2/chtypes.h is regenerated; the
fingerprint is unchanged (sha256:78518cd5…6044b4e).

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

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

# Conflicts:
#	examples/python/uv.lock
#	examples/rust/Cargo.lock
#	go/internal/ocifetch/useragent.go
#	python/pyproject.toml
#	python/uv.lock
#	rust/Cargo.lock
#	rust/Cargo.toml
#	ts/package.json
26.7 is served but unsupported, frozen on 26.7.19.5. lines.json now
carries that patch and the generator renders it marked frozen. A
served-unsupported patch stays optional and is not checked against rows.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Subqueries and reads of tables, files, remote hosts and dictionaries in a
CREATE, a filter or a Values expression decline instead of executing.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Supported: 26.3, 26.8, 26.9 and 26.10; 26.7 is served but unsupported.
Dated measurement records are left as written; the filter lift table
gets a note that it predates 26.10.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
EricAndrechek and others added 5 commits November 3, 2026 16:33
chtypes models one exact patch per line. The 26.8 and 26.9 patch bumps
moved only the enum-literal comparison, in both directions; the 26.3
bump was not measured.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Both complement the spec's Known limitations and point to it.

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

The statement is prose in spec/abi-v2/docs.md, outside the fingerprint; the
generated reference and header comment follow.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Adds in-set-reads-column and widens the expression-reads-storage trigger
text, copied byte for byte from the artifact producer's newer build.

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

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

This branch has not been deployed

No deployments
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