tables: the block opens a const region and reads const rows (#455) - #673
Merged
Conversation
test/tables/block_const_main.cpp loads the pinned block image, holds it as
a `const uint8_t *` from that moment and opens it with no cast, then walks
its rows through a read-only view and compares them against the same bytes
opened writable. Makefile gains `tables-block-const`, its sanitized twin and
`tables-block-const-negative-control`, and `tables-block` runs all three.
It is RED on this commit, which is the point of landing it first:
error: no type named 'Const' in 'blockdemo::RenderFrameBlock'
error: no template named 'TableBlockConstRows'
error: no template named 'TableBlockConstSpan'
`BlockOpen` takes `void * base` and the row views hand back mutable rows, so
a consumer of foreign bytes gets write access and a const region cannot be
opened at all (docs/SPEC-TABLES.md §19.2).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
internal/codegen/cpptable/block.go gains three things, and the producer's
path gains nothing:
* TableBlockConstRows<T> and TableBlockConstSpan<T> in the shared runtime,
the same two views with const on every pointer they hand out. Both are
runtime names, so no per-table spelling is claimed (SPEC-TABLES §11).
* <Name>Block::Const, a member type of the handle that already exists, so
it claims no name of its own. It carries the same three facts with const
on both pointers.
* bool <Name>BlockOpen( <Name>Block::Const &, const void *, int64_t,
TableRefuseReason * = NULL ), and the row accessors overloaded on the
const handle.
The CHECK is now one body per table, in an anonymous namespace in the .cpp,
answering the used extent beside the verdict: both overloads run the same
clauses in the same order and name the same reason on the same refusal, so
the producer's path and the consumer's cannot drift. Begin, the fill
accessors and the typed base a worker indexes are untouched.
docs/SPEC-TABLES.md §19.2 states the overload, the const handle and the two
const views, and §19.5 states the gate and its control.
Goldens moved, and only by the added surface:
generated/bench/tables/cpp/BenchTableBlock.h +88
generated/bench/tables/cpp/BenchTableBlock.cpp +94 -8
testdata/golden/wide/cpp/CaptionBlock.h +65
testdata/golden/wide/cpp/CaptionBlock.cpp +47 -4
No wire pin moved: testdata/wire/ is byte-identical, because a C++ overload
changes no layout fact the BUILD VERSION is taken over (SPEC-TABLES §20.1).
The gate is green and its control is red on the write:
OK: a const block region opens with no cast, and its rows read back
read-only (docs/SPEC-TABLES.md §19.2)
error: cannot assign to return value because function 'operator[]'
returns a const value
RenderFrameShipsSpan( block )[0].object_id = 1;
note: function 'operator[]' which returns const-qualified type
'const blockdemo::RenderShip &' declared here
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
rowan-claude
force-pushed
the
contract-cook-bool-const-block
branch
from
September 7, 2026 10:47
7101254 to
74fd04c
Compare
…ase and iterator too (#455) 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 C++ column's CONTRACTION pass, two gaps in the table runtime. One of the
two landed. The other is refused by the page, and this body says why rather
than leaving a reader to find out.
Closes #455
#455: the block opens a const region and reads const rows
RenderFrameShips( block )handed back mutable rows whether the block camefrom the producer's
Beginor fromBlockOpenover bytes another languagehanded over, and
BlockOpenitself tookvoid * base, so a consumer holdingan mmap'd read-only file had to
const_castto open it at all. C# alreadysplits that surface (
ref readonlyiteration,ReadOnlySpan<Row>) and Rustreturns
&[Row]; C++ alone gave a reader write access.Red first.
test/tables/block_const_main.cppand its two Makefile targetslanded in 7e7b4c6, one commit before the fix, and that commit is red:
The fix, in
internal/codegen/cpptable/block.go:TableBlockConstRows<T>andTableBlockConstSpan<T>in the shared blockruntime: the same two views the producer has, with
conston every pointerthey hand out. They are runtime names, so no per-table spelling is claimed
(SPEC-TABLES §11).
<Name>Block::Const, a MEMBER TYPE of the handle that already exists, so itclaims no file-scope name of its own. Same three facts,
conston bothpointers.
bool <Name>BlockOpen( <Name>Block::Const &, const void *, int64_t, TableRefuseReason * = NULL ), and the row accessors overloaded on the consthandle, so a call site written against §19.2 reads the same either way.
The check is now ONE BODY per table, in an anonymous namespace in the
.cpp, answering the used extent beside the verdict. Both overloads run thesame clauses in the same order and name the same reason on the same refusal,
so the producer's path and the consumer's cannot drift.
Begin, the fillaccessors and the typed base a worker indexes are untouched, and the fill
refuser still passes over the same markers.
The controls. The gate runs plain and sanitized; its negative control is a
COMPILE control, because a green run can never tell a read-only view from a
view in name only. The same program, one assignment through the const view
added by
-DBLOCK_CONST_WRITE, must fail to compile:The page. SPEC-TABLES §19.2 states the overload,
<Name>Block::Constandthe two const views, and §19.5 states the gate and its control.
Goldens moved, and only by the added surface. No wire pin moved:
testdata/wire/is byte identical, because a C++ overload changes no layoutfact the BUILD VERSION is taken over (§20.1).
generated/bench/tables/cpp/BenchTableBlock.hgenerated/bench/tables/cpp/BenchTableBlock.cpptestdata/golden/wide/cpp/CaptionBlock.htestdata/golden/wide/cpp/CaptionBlock.cppEach is the two view templates in the shared runtime, one
Constmember typeand one
BlockOpendeclaration per block-formed table, and in the.cpptheopen body moved into an anonymous namespace with the two overloads over it.
#271: NOT DONE, and the page is why
The issue asks that a cooked
boolbyte of 129 be refused byOpen, with thecheck placed in
<X>OpenWalk. Every part of that premise has moved since theissue was filed on 2026-09-02, and implementing it would knowingly turn three
standing gates red. It is left open, unclaimed by this PR, for a ruling.
There is no
OpenWalk. §11 records it as the one name ever removedfrom the claimed set: it named wire v1's validating walk, §7's
Openis aheader match with no walk in it, and a test now asserts
<X>OpenWalkisLEGAL for a user schema. Re-claiming it takes that name back.
Openreads no byte of the data part, by design. §7: "There is NOPER-NODE VALIDATION AT LOAD, ever, and that is not a cost saved but the
design: a per-node pass over a catalog-scale file is the parse the whole
form exists to delete." §7.4: "Nothing else is read. Not a scalar."
An owner ruling one day AFTER the issue settles it. §13.4, dated
2026-09-03: "OK to be clear, cooked data is generally trusted and will be
loaded from disk", and, on the question the issue actually raises, "If we
have concerns, then we should sign it." / "We just have to load the
data." Integrity is one verification over the whole file before
Open,never per-node checks in the loader.
Three gates go red.
tables-cook-open-walk-negative-controlexists toprove that a walk in
Openis a defect and prints "a walk in Open turns theopen-cost gate RED";
make/cs.mkcarries its twin. The cook forgeryfuzzer's oracle is "a mutation inside the DATA part must not change Open's
answer AT ALL, which is the O(1) promise stated as a property a fuzzer can
falsify", and a
boolbyte is in the data part. The open-cost gate itselfmeasured 14.4 ns at 1.5 MB and 14.4 ns at 157 MB on this branch, ratio
1.000.
A refusal here is not the C++ lane's to make alone. The forgery corpus
is a CROSS-LANGUAGE registry:
testdata/conformance/tables/MANIFEST.txtsays a
forgeryrow is "one damaged fixture and the verdict everyimplementation owes it", and §7.5's cross-implementation lock has the C++,
C# and every other
Openpointing at the same bytes. Acook_bool_129rowwith the verdict
refuseobligates all nine backends; adding it to the C++reference alone would break the lock rather than close the gap.
The gap the issue names is real: a
boolholding 129 is a traprepresentation, and a caller reading a cook whose provenance it doubts cannot
check the region itself. The in-design home for that check is the TOOL, not
the loader:
schema cook-check's pass two already walks every node and §7.4enumerates what it reads, so the clause would go there and §7.4 would gain a
line. That is a design decision and a nine-backend conformance question, so it
is left to Glenn rather than taken here.
What ran
Rebased onto 59cd186, so #674's list-walk fix and #660's toolchain gate are
both under it.
make test SCHEMA_SKIP_LEGS=cs,dart,elixir,java,jsexits 0, the wholechain. Five of the nine pinned toolchains are absent on this machine, and
make test refuses a missing pinned toolchain by name, and names a skip that is asked for (#599) #660's gate refuses by name rather than skipping quietly, so the skips are
named on purpose.
tables-blockruns inside that chain and carries the newgate: two OK lines (plain and sanitized) and one negative control that turns
the compile red.
make tables-cook-open, and all three oftables-cook-open-lengths-negative-control,tables-cook-open-root-negative-controlandtables-cook-open-walk-negative-control. The open-cost gate reportedcook open is O(1) in the file's size: Scene at 1572832 bytes opens in 14.4 ns, at 157286368 bytes in 14.4 ns, ratio 1.000.go test ./...clean.go test ./internal/goldens -updateand the benchtable regeneration. The full
make update-goldenstarget's per-languagelegs (
GOLDENS_LEGS) need dotnet, which is absent here; nothing they pin istouched by a C++ block header, and CI's
generatedandcpp-lockjobs pass.