tables: string, bytes and flags defaults, and was on a table declaration (#396) - #576
Merged
Conversation
…ion (#396) The three defaults ride the table wire as a scalar's does: a field holding its declared default elides, an absent field reads as it, and the default is a projection, cook-projection and baseline fact. The C++ reference and the tool carry them; every other target refuses a unit that declares one, naming the follow-on. A table declaration takes was. Its node type id is the hash of the old name, so every stored record still reads, and every id derivation reads the wire name: the node record, the cooked directory, the announced vocabulary, the baseline and the build version. The baseline keys a table by its wire name, records the declared name beside it, and refuses a second rename aimed at the intermediate spelling. W1/W2 are the evolution pair, with three pinned instances, three silent report rows, and tables-was-negative-control, which strips the attribute and watches unknown count. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…396) The versioning table's default-change row reads refuses, the competition matrix's defaults and rename rows move to partial with their footnotes saying what is built and what is owed, and the where-they-are-ahead entry names the table beside the field. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The reference leg compiles W1Table.cpp and W2Table.cpp and includes their headers, so the generated directories join CONFORMANCE_INCLUDES. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… W rows join the fuzz The oracle's storage map was keyed by the DECLARED name's type id, so a pointer target renamed under `was` commanded no region bytes in the oracle and wireVerdict refused the seed. It reads st.WireName() now, and the wire-fuzz driver registers tblw1.Fleet and tblw2.Fleet, so the six W seeds are live (121 seeds over 36 roots, 10 absent, 0 divergences). With the old key and the rows registered the fuzz goes red on w2_fleet, LoadMeasure 360 bytes against a framing of 200. Also from the cold read: SPEC.md no longer says a table declaration takes no qualification, the held-back-id refusal case in internal/check is named for what it tests (a valued key a table declaration does not take), and the added prose in SPEC-TABLES.md, the Makefile, W1.schema, W2.schema and the valuedefaults refusal carries no em dash. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
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.
The first of the two
wasrows (#396, adopt items 2, 3 and 4): defaults forstring(N),bytes(N)andflagsfields, andwason a table declaration, in the C++ reference, the tool, the baseline and the pages.What rides
The three defaults. SPEC §4.2's
Defaultproduction takes a quoted string forstring(N)andbytes(N)(at most N bytes, valid UTF-8 for a string) and a brace list of variant names for aflagsfield (caps Caps = { Jump, Crouch },{}the zero mask). On the table wire a field at its declared default elides and an absent field reads as it, which is the scalar rule with nothing added, so an EMPTY string rides when the default is not empty. The default is a projection fact, a cook-projection fact and a baseline fact (default=bytes:<hex>for a string or bytes default, the mask for a flags default). The C++ reference and the tool carry the three; every other backend refuses a unit that declares one, naming the follow-on (compiler/valuedefaults.go,TestValueDefaultsAreCppOnly).wason a table declaration.table Ship | was = "Vessel": the node type id is the hash of the OLD name, so every stored record still reads, and every id derivation reads the wire name: the node record, the cooked node directory, the announced vocabulary, the baseline and the build version. Awasrename of a table moves neither id. The refusals are the field's:wasnaming the table's own name,was = "", an alias colliding with a live table's type id or taking a held-back id, andwason atypedeclaration, which rides by value and has no node type id to keep.The baseline keys a table by its wire name and records the declared name beside it (
table Vessel name=Ship, on the renamed line only, judged on nothing), so a rename underwasregenerates every line byte-identically and the rendering version is unmoved. A second rename aimed at the intermediate spelling is refused naming the first (TestTableWasChainIsRefused). A string, bytes or flags default changed, added or removed is refused as a scalar's is (TestValueDefaultsAreJudgedAsDefaults), with the attribution control (thedefaultrule removed, the edit passes).The projection.
TestTableRenamedUnderWasMovesNeitherId: the rename underwasmoves neither the protocol id nor the build version, and the discrimination control renames the table bare and watches the build version move.TestValueDefaultsProject: each of the three defaults moves both ids when changed.The corpus.
test/tables/W1.schema/W2.schemaare the evolution pair: W1'sVesselis W2'sShip | was = "Vessel", and both carry a string, a bytes and a flags default beside atypea table reaches with a string default of its own. Three pinned instances (w1_fleet,w1_fleet_default,w2_fleet) ride every conformance surface,w2_fleetbyte-identical tow1_fleet, type id included, andw1_fleet_defaultthe empty wire. Three report rows pin the silent cross reads:Gates and their negative controls
make tables-was-negative-controlcompilestest/tables/was_control_main.cpptwice, against the shipped W2 and against a W2 with| was = "Vessel"stripped and regenerated by the shipped compiler, and reads the samew1_fleetgolden through both:The Go gates, each with the control the file already runs on every case:
internal/check/was_test.go:TestValueDefaultAndTableWasRefusals, seventeen refusals by name (a default past the capacity, not UTF-8, a quoted string on a scalar, a brace list on a scalar or an enum, a name that is not a variant, a repeated name, an integer on a flags field, a wstring default,wason atype, a table'swasnaming itself, empty, unquoted, bare, colliding with a live table, and a valued key a table declaration does not take), andTestValueDefaultsAndTableWasResolvefor what each accepted spelling lands in the IR.internal/baseline/was_test.go: the three tests above, with the discrimination control (a table renamed bare warns thatVesselis no longer in the closure under that name) and the attribution control.ir/was_test.go,internal/format/was_test.go(the three defaults and the table attribute throughschemafmt, idempotent),compiler/valuedefaults_test.go(eight ports refuse, naming the fields and--lang cpp).test/tables/main.cpptest_was_rows: everything at its default is the empty wire, an absent field reads its declared default, a string cleared to""rides, and the cross read in both directions with a byte-identical re-save.The zero-cost law (2026-09-05)
This PR adds no counter, reason or descriptor. The one emitter change on a read or write path is the elision test for a string, bytes or flags field, and for a field with no declared default it emits the text it emitted before: the committed
generated/tree, the bench unitgenerated/bench/tables/cpp/BenchTableTable.hincluded, regenerates byte-identically under this compiler (CI's staleness check, andgit statusclean aftermake testhere).The sitting anyway, per the law. The table read and write benchmarks over the existing corpus (
bench/corpus/BenchTable.schema,corpus_id b51387f36d9b59c4, 2147 wire bytes per record), before at45888e55(origin/main) and after atad7213ee(this branch), the samebench/tables/cpp/table_main.cppagainst each tree'sgenerated/bench/tables/cpp/BenchTableTable.h. The two leg binaries are byte-identical (cmpclean, 106408 bytes each), so the sitting is a noise reading of one machine code.MacBook Air M2, 2026-09-05 12:39, five interleaved rounds (§2.4),
--round Keach, before then after within a round, one-minute load 2.78 when the sitting started and 3.2 to 3.9 while it ran, with three other builders compiling in sibling clones (no core pinning).Unchanged within noise: write 0.6% apart, round_trip 0.03% apart, each side's own spread wider than the gap. No cost measured, none landed.
Pages
docs/SPEC.md§4.2 (theDefaultproduction and the three defaults, the attribute vocabulary, thewasparagraph),docs/SPEC-TABLES.md§4 (absent reads the declared default), §4.1 (two rows: a table renamed underwas, and renamed a second time), §5 (a table's name is identity too), §15 (the compile-time refusals), §18.1 and §18.2 (the rendering and the chain rule),docs/VERSIONING.mdpromise 3 and the edits table,docs/USAGE.md(defaults, and the table rename),docs/COMPETITION.md(the defaults and rename rows move to 🔶 with their footnotes saying what is built and what is owed).#366
The row string/bytes/flags defaults and table was (#396) moves to ✅ in the cpp column. Every other column stays ❌ behind the named refusal.
Silences the page left
scale Vec3 = { 1.0, 1.0, 1.0 }) is the adopt-later row of Language-level features from FlatBuffers, Avro, Protobuf and Cap'n Proto: four to adopt, seven later, eighteen declined #396, after Every type the type wire carries rides in a table: fixed, ufixed, 128-bit, user types inline, user tables inline, pointers to user tables #390.wstring(N)field takes no specified default (SPEC §4.12 stands).Gate state
make testwhole on this branch, green: the C++ table tests plain and under ASan/UBSan,make tables-wire-fuzz N=20000on both builds withtblw1.Fleetandtblw2.Fleetregistered in the driver, so the six W seeds are live (wire-fuzz: seed 24845619678, 121 seeds over 36 roots, 10 seeds absent (roots the leg has no codec for), 107207 enumerated + 20000 random = 127207 mutants, 0 divergences, and each W golden replayed through both units, 0 divergences), and the oracle keyed by the DECLARED name instead of the wire name goes red on the same run (FAILED after 80727 mutants: LoadMeasure asks for 360 region bytes; the framing commands exactly 200, corpus seed w2_fleet), every wire-fuzz negative control red,tables-was-negative-controlas quoted, the conformance leg (wire 63/63, message 11/11, report 53/53, json-read 59/59, json-write 59/59, json-hostile 125/125, cook 6/6, cook-write 92/92, cook-foreign 6/6, block 2/2, block-foreign 2/2, block-dump 2/2, forgery 11/11, cook-forgery 111/111), andgo test ./.... MacBook Air, sequential, one-minute load under 3 at the start.🤖 Generated with Claude Code