docs/SPEC-TABLES.md §2.8: maps, the specification - #479
Conversation
4c5dd69 to
d70bab4
Compare
…#380) The owner reversed the after-3.0.0 sequencing (#380, 2026-09-04): maps land in the C++ reference and the tool inside spec finalization, before the port sweep. The page said otherwise in two places and was stale in four more. - The BACKEND STATUS paragraph and THE SEQUENCING paragraph move from "no backend, and no declaration reaches it — after 3.0.0" to the register every other landed construct uses: the C++ reference and the tool carry it, every other backend refuses a unit that declares one by name, the ports are a named follow-on. The closing confirmation keeps its content and loses its dependence on the freeze: the construct spends nothing the release freezes. - The VALUE list gains `*bytes` and `*string` (#428) and `?[N]T` / `?[..N]T` (#437) — every spelling a table field can hold today. - The ENTRY's two constant field ids are stated as constants of the RULE rather than beside it: today's fold (`key` 0xA079, `value` 0x9194) and, under the uniform 64-bit wire (#435), `fnv1a64` of the same two names (0x3DC94A19365B10EC, 0x7CE4FD9430E80CEA), carried in that wire's id table in first-use order like every other id. §5's constants paragraph says the same. - The POINTER WALK over a map is stated (#438): a map is a by-value edge of the ONE declaration-order walk, reached where it is declared, its entries visited in ascending key order — the order the wire carries — with each entry's value descended before the next entry. §3.1's by-value edge list gains the entry. Two reconciliations, named because they change an argument rather than a status line: - The SHOULD answer's decisive reason was "a dedicated map kind after 3.0.0 would make every 3.0.0 reader meet framing damage". Landing before the freeze retires that reason — a kind spent now is inside the closed set. The kind still stays unspent, on the rule that actually governs it: a kind is spent to close a SILENT edit (§3.1, §3.2), and a map and an array of pairs are the same data read correctly either way. The migration argument stands. - §15's follow-on row said the construct is designed and unbuilt, and deferred the optional runtime index behind a bench number. The row becomes what is actually outstanding — the eight ports — and the index ships with the construct in the reference: it is never stored and no golden names it, so what the bench defers is the SIZE AT WHICH A CALLER REACHES FOR IT, not the surface. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…y construct (#380) The sequencing ruling stands — maps land now, before 3.0.0 and before the port sweep. What the status paragraph must not do is claim a codec before it exists: the language half lands first (the spelling, the key rules, the generated entry and the name it claims), the C++ reference and the tool follow, and until a backend's codec lands it refuses a map-bearing unit by name (§11) rather than emitting a half-codec. §2.8's status paragraph, THE SEQUENCING and §15's row all say that. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
645d175 to
6cd17b9
Compare
Rulings on the #479 cold read (maps spec, docs/SPEC-TABLES.md §2.8)Numbers follow the reader's report (sections 1 to 5). Line numbers there are at 6cd17b9 on maps-spec. Every ruling below is a rule the page states as present fact, in the page's voice, with no history, no plan, no owner quotation. 1. Underdetermined1.1 The key before the slot. Before an entry's body decodes, the reader scans the entry's field headers for the key's id and reads the key (a bounded string or an integer, always a primitive). The scan decides the slot: ascending lands the body in the next slot; equal resets the previous slot to defaults and decodes the body into it (last wins whole); descending stops the map as malformed, the parent continues. An entry whose body carries no key field has the key's default. Where the body repeats the key's id, the scan reads the occurrence §3's repeated-field rule keeps. The writer emits the key first in every entry, so on any wire this schema wrote the scan ends at the first header; the rule is the scan, not the position. 1.2 Keys never clamp. An entry whose key does not fit the reader's bound (longer than N, or one a string value would clamp) is skipped by its L and counted clamped, one per entry. The order check compares the wire keys of the entries that land, so a skip cannot reorder or collide. A tightened key bound is therefore lossy by whole entries and never malformed; a widened one is lossless. A key a string value would refuse as malformed makes the map malformed. Rewrite L1538 to L1541 to this. 1.3 Key kind. The reader's declaration is the reference, never the first entry. At the first entry whose key kind disagrees with it, the map resets to empty, ONE kind_mismatch is counted for the map, and the map's remaining bytes are skipped by the map's L: nothing after that entry is decoded or counted. Events counted inside earlier entries of that map stand. A value field of the wrong kind is §4's ordinary per-field event inside the entry: the value reads its default, the entry stays. A map header whose element kind is not 13 is the ordinary array kind mismatch. 1.4 One report per wire. Delete the builder forgiveness. LoadBuilder applies the same rules as Load and produces the same five counters and flag, so §4.2's oracle and §17.5's differential hold. A hand-made body must be sorted like any other; there is no tool path. 1.5 LoadMeasure. A map's term is N × sizeof(Entry) padded to alignof(Entry), at every depth. On refusal LoadMeasure answers with the spelling it already uses for a wire it refuses (the worker finds it on the page and cites it). §4.2's EXACT claim is scoped: exact for a wire that reads with an empty report; a read that reports uses at most the measure (an empty map on kind mismatch and a skipped entry both leave slots unused). Restate §4.2's bound from the smallest wire footprint that yields one storage unit, which is now an entry, not a record. 1.6 Build version and baseline. The entry record is anonymous in both. It is identified by the holder's wire id plus the field's wire id, never by its generated name. §20.1's closed table gains the map field line (an array line, element kind 13, bound N, key kind, key bound) and the entry's record line keyed as above; §20.2's grammar gains the tokens; the worker mirrors the existing token forms exactly. §18.1's shape gains a map value carrying key kind and key bound. The verdict for [..N]Pair to map[K]V is WARN, with the reason: the bytes are identical when Pair's fields are exactly key and value, and the read gains the order check, so a wire whose pairs were not ascending reads short. Strike "silent and safe". §4.1's table gains §2.8's four evolution events. 1.7 Entry name. Entry with the field's name in PascalCase by §11's rule, cited. A map value that is itself a map names its entry ValueEntry. The entry is declared in the holder's file, immediately before the holder.1.8 Claimed names. §11 claims the map surface: 1.9 An unreached non-empty map slot is refused by Cook and Lock, the same refusal §7.6 gives a pointer there, cited. 1.10 The count is int32 like every companion; §2.2's extent cap is the cap; a wire N above it is refused as any array's is, at both widths. 1.11 Integer key text is parsed by §16.2's integer rule and nothing else, so -0 is zero and anything §16.2 rejects is malformed. A malformed key stops the read by §16.1's rule; say so in §2.8 rather than leaving it to the cross-reference. 1.12 The const Find on map[K]*T returns what a pointer field's accessor returns (cite the convention). Iteration yields the stored key in the form a string field's accessor yields. Insert returns NULL for a key that does not fit and for a full map alike; NULL means not inserted, and a caller who needs the reason checks the key's length first. 2. Contradictions2.1 A map of the holder's own type is refused as a by-value cycle (§2's rule), not for infinite size. Fix the reason. 3. The #435 seamOne sentence at the head of the wire bullets: these widths are §3's today; under schema#435 ids are references, L and N are canonical LEB128, and the terminator is the zero reference. Mark the cost table as today's wire. Apply 1.10 at L1606. 4. The testsRewrite the control list so every control names the corpus row or instance that makes it red: #1 an instance built out of key order; #2 the shuffled report row; #3 a duplicate whose repeat elides a field the first occurrence set; #7 the report row under a changed key kind; #9 leaves the control list, it is data; #11 an erasing instance; #13 is deleted with the tool path; #15 the value half, not the counter; #17 the key bound as the isolating half. Add the missing controls: the walk-order pin (a map with *T values declared before a pointer field that reaches a shared node first), the parent-continues half of the descending rule, ONE kind_mismatch when the disagreeing entry is a later one, LoadMeasure exactness over a map of maps, and cook-check's entry-array check. Drop "reds" as a verb and every gate name the page does not define. 5. ProseRemove the owner quotations, the history, the plans and THE SEQUENCING. State each twice-stated fact once. Split L1463 to L1468. Fix the log formula to floor(log2 n) + 1. Fix the broken bold span. No em dashes in rewritten prose. British spellings outside §2.8 are #402's and stay. |
A cold read of the maps design finds four rules underdetermined, two sentences that contradict the rest of the page, and a control list that names no corpus row. §2.8 now states each of them as present fact, and the sections it touches say the same thing. The rules the page did not carry: - the KEY is read before the slot is chosen, by a scan of the entry's field headers, so field order inside a body stays non-contractual - keys never clamp. An entry whose key does not fit the reader's bound is dropped and counted clamped, one per entry, and the order check compares the wire keys of the entries that land - the key kind is the READER's declaration. At the first entry that disagrees the map reads empty, one kind_mismatch is counted for the map, and the rest of the map is skipped by its L - one report per wire. The region load and LoadBuilder apply the same rules, so §4.2's oracle and §17.5's differential hold over a map - LoadMeasure's term is N x sizeof(Entry) rounded up to alignof(Entry) at every depth, and a wire it refuses answers the -1 every measure's refusal answers. §4.2's EXACT claim is scoped and its bound restated from an entry rather than a record - the entry is ANONYMOUS in the build version and in the baseline, keyed by the holder's wire id and the map field's wire id, so a was rename moves no line. §20.1, §20.2 and §18.1 carry the tokens - the entry's name, its PascalCase, the nested map's form and the file that declares it - §11 claims the eight names a map takes against its field, and the two runtime types beside them - the slot's count is int32 like every companion, and §2.2's extent cap is the cap - an integer key's text is §16.2's integer rule and nothing else, and a malformed key stops the read where §16.1 stops it - the const Find on map[K]*T answers what a pointer field's accessor answers, and Insert answers NULL for not inserted The contradictions: - a map of the holder's own type is refused as a by-value cycle, not for infinite size - cook-check reads containment, alignment, fit and no overlap, not the offset the layout rule computes, so §7's independence sentence stands - an empty map is elided by §3's rule, not §2.3's - the [..N]Pair edit is not silent and safe. The read gains the order check, so the baseline warns - a map's entry is the one exception to "a root is any table", and §7 says so where the rule is stated The wire widths are marked as the wire as it stands, with schema#435's named beside them. Every negative control names the corpus row or instance that meets it and the one instrument that goes red, and the missing controls are added: the walk-order pin, the parent-continues half of the descending rule, one kind_mismatch from a later entry, LoadMeasure over a map of maps, and cook-check's entry-array check. The status paragraph, the sequencing, the owner quotations and the plans are gone. The page states the contract. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ent (#380) The three-frames table is the single statement of what an edit does, and it had no map row. It gains one: a map's key kind changed or its key bound tightened, across the read report, the baseline and the build version. The read report paragraph called duplicate the text form's counter. It has one source on each side, and the wire's is a map's repeated key (SPEC-TABLES.md §2.8, §4). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The maps specification (#479) landed first, so the baseline rendering version on the page is main's constant plus two, and the four overlaps resolve to both sides: the pointer walk lists a map entry beside the set arm, §18.2 warns on a tightened range whether it is a field's or an arm's, and §20.2's field grammar keeps `array=map` while dropping the `stride=` the emitter puts on `slot` lines only. `elem=` is stated for an array, which is what an `arm` line carries. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…nd SPEC.md carries the grammar (#380) The FRONT END's half of §2.8 and §11, and the SPEC.md lines the construct was missing. - A QUALIFICATION OR A DEFAULT ON THE KEY is a refusal with the page's own sentence, not a parse error about a bracket. The grammar takes `map[uint32 | max = 4]int32` and `map[uint32 = 5]int32` on the terms it already takes `map[?uint32]`, so the diagnostic names the real problem: a key is an identity, and clamping an identity merges two entries. - THE ENUM-KEY SUGGESTION never names a spelling the next compile refuses, and it keeps the value's array bound. `map[E][..4]int32` suggested `[E]int32`, a different declaration; `map[E]*V` suggested `[E]*V`, which the checker refuses as a named follow-on. The replacement clause now asks whether `[E]T` takes the value at all, and says what to do instead when it does not. - THE MAP CLAIMS EIGHT NAMES against its field, on the rule §11 already states for the block form's row accessors: `<Table>` plus the field's PascalCase, then Entry, Insert, Find, Erase, Each, IndexMeasure, Index and IndexFind. The runtime names TableMap and TableMapIndex join internal/tablenames on TableKeyed's terms, claimed with the construct rather than with the codec, because a name freed now is a collision the day the codec lands. - THE ENUM-KEY TEST fixture is renamed. It was an enum literally named `E` against a diagnostic that prints `[E]T`, so it could not tell a substitution from a hardcoded string. It is `ShipType` now. - ir.MapEntryStructs, ir.MapKeyIsString and ir.HasMap go: scaffolding with no caller outside the tests. ir.MapFields lists the fields an AUTHOR WROTE, so a target's refusal no longer names `FleetLoadoutsEntry.value`, a generated name in no source file. SPEC.md gains `map` in the reserved words and a `Map` production in the `Type` grammar, with the same TABLE BODIES ONLY note the `?` and `*` productions carry. #479 is SPEC-TABLES.md only, so nothing else covered it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…nerated entry (#380) (#487) * tables: the map front end — the `map[K]V` spelling, its key rules and the generated entry (#380) The scanner takes `map` as a keyword; the AST carries the value as a whole FIELD spelling, so a map of arrays, of optionals and of maps are one production; the parser reads `map[K]V` wherever a field type stands. The IR gains ir.TMap and Field.MapEntry — the generated `{ key, value }` table, a real table of the closure with its own record, Reset and descriptor. ir/tablemap.go carries the derived facts: the entry's name, its two constant ids as ordinary hashes of two ordinary names, the census a refusal names. VariableTables gains §2.8's clause (a map is a variable edge whatever its key and value are) and TableClosure reaches through the entry. The checker resolves the value through the ordinary field path and holds every rule §2.8 states, each refused by name with the page's own reason: a map in a `type` body, an enum key (naming [E]T), bool, float, flags, bits(N), bytes(N), fixed, a type, a table, a pointer, an optional and a union keys, a bound on the map, ?map, a default, an attribute, the by-value cycle through the entry, and a declared table under the claimed <Table><Field>Entry name. Every other backend refuses a map-bearing unit by name, through compiler/tablesmaps.go per the registry split. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * tables: the map's wire kinds, record piece and every backend's refusal (#380) The IR facts a map's codec will read, and the gate that keeps a half-codec from being emitted before one exists. - ir/tablekind.go: a map rides as kind 14 over element kind 13 — an array of the generated entry, no new kind and no new framing (§2.8, §3) — and TableTypeSpelling renders `map[K]V` so a diagnostic and a descriptor name the declaration the author wrote. - ir/blocklayout.go: a map field is ONE sixteen-byte piece at eight (§2.8, §7.2) — an int64 self-relative reference and a uint32 count, then padding — one piece and not two for the reason the block form's out-of-line triple is one: both backends spell it as one member of a TableMap type, and a port that walked two would account for twelve bytes where sixteen are written. - Every backend refuses a map-bearing unit by name, the C++ reference included, until its codec lands (compiler/tablesmaps.go). The refusal names the fields and schema#380, and target_cpp drops its call and registers through registerMapCarrier when its half lands. - The zero-cost gate's header scan gains the map symbols (§2.2, §2.8): every unit it scans is map-free by construction, and the symbols say so mechanically rather than by inspection. - The parser takes `?` on a key so the checker's OPTIONAL-key diagnostic lands where the spelling is, rather than a parse error naming a bracket. Held by: compiler/tablesmaps_test.go (the derived facts at three depths, the two constant ids, every target's refusal, and a map-free unit untouched) and 24 new rows in internal/check's refusal suite. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * tables: the carrier registry's second refusal shape, held by a test (#380) refuseMaps has two shapes — no carrier yet, and a carrier named — and only the first had a call site. The test registers cpp through registerMapCarrier and holds the second, so the day target_cpp.go registers for real the message it produces is already pinned. It also keeps the registry function from being dead code between the two PRs. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * tables: §2.8's map example joins the doc-examples gate (#380, #460) #482 excluded the block because maps did not parse. They do now, so the block is anchored like every other declaration example and the header comment says what the gate actually is: the PARSER's, so a block enters the moment its construct has a grammar, whether or not a backend carries the codec. Negative control: respelling the example to the REJECTED map<K, V> form turns the gate red, naming the page, the anchor and the line. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * tables: a map's spelling names the value's star (#380) ir.TableTypeSpelling rendered map[uint32]*ShipConfig as map[uint32]ShipConfig, so a diagnostic and a descriptor would have named a declaration nobody wrote — and map[K]T against map[K]*T is exactly the edit §3.1 spends a kind to keep from being silent. Pinned by TestMapTypeSpelling over the three shapes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * tables: schemafmt keeps the map spelling, and the pointer star binds to its type (#380) Every command formats a source in place before it processes it, so a spelling the formatter does not know is a spelling it silently rewrites. `needSpace` had no case for the `map` keyword and none for the `]` that closes a map key, so §2.8's own example came back as `map [string(32)]ShipConfig`, `map [uint32] * ShipConfig` and `map [uint32] ?[..4]int32`: idempotent, and away from the page for good. The `] * ` half is not new. `[..2]*Chunk` in the stream corpus has been stored as `[..2] * Chunk` since pointers landed, because type position was recognized only at index 1. It is the same defect one line away, so it is fixed here. Type position is index 1, the `]` that closes an array bound or a map key, and the optional `?`. No expression in this grammar ends in either, so the rule takes no case away from multiplication. The formatter's SAFETY CHECK was blind to the construct too. Format re-parses its own output and compares the two ASTs structurally, and the fingerprint rendered no map at all, so two different maps and a map against a bare field all fingerprinted alike. It renders the whole field type now: the key, the bound, the star and a nested map included. The gate reads §2.8's example OFF THE PAGE and compares the formatted bytes, with the mangled spellings as its controls. Each is an input schemafmt itself used to produce, and each must come back as the page states it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * tables: the key takes no qualification, the map claims eight names, and SPEC.md carries the grammar (#380) The FRONT END's half of §2.8 and §11, and the SPEC.md lines the construct was missing. - A QUALIFICATION OR A DEFAULT ON THE KEY is a refusal with the page's own sentence, not a parse error about a bracket. The grammar takes `map[uint32 | max = 4]int32` and `map[uint32 = 5]int32` on the terms it already takes `map[?uint32]`, so the diagnostic names the real problem: a key is an identity, and clamping an identity merges two entries. - THE ENUM-KEY SUGGESTION never names a spelling the next compile refuses, and it keeps the value's array bound. `map[E][..4]int32` suggested `[E]int32`, a different declaration; `map[E]*V` suggested `[E]*V`, which the checker refuses as a named follow-on. The replacement clause now asks whether `[E]T` takes the value at all, and says what to do instead when it does not. - THE MAP CLAIMS EIGHT NAMES against its field, on the rule §11 already states for the block form's row accessors: `<Table>` plus the field's PascalCase, then Entry, Insert, Find, Erase, Each, IndexMeasure, Index and IndexFind. The runtime names TableMap and TableMapIndex join internal/tablenames on TableKeyed's terms, claimed with the construct rather than with the codec, because a name freed now is a collision the day the codec lands. - THE ENUM-KEY TEST fixture is renamed. It was an enum literally named `E` against a diagnostic that prints `[E]T`, so it could not tell a substitution from a hardcoded string. It is `ShipType` now. - ir.MapEntryStructs, ir.MapKeyIsString and ir.HasMap go: scaffolding with no caller outside the tests. ir.MapFields lists the fields an AUTHOR WROTE, so a target's refusal no longer names `FleetLoadoutsEntry.value`, a generated name in no source file. SPEC.md gains `map` in the reserved words and a `Map` production in the `Type` grammar, with the same TABLE BODIES ONLY note the `?` and `*` productions carry. #479 is SPEC-TABLES.md only, so nothing else covered it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * tables: a map's entries are never rows, and neither projection sees the entry's name (#380) The DERIVED FACTS half, and the cook projection's form version with it. THE BLOCK FORM. §2.8 states that a map's entries are never rows, and it was not so. `blockFormable` asked only whether a table is variable-length, and `FleetShipsEntry`, a `string(32)` key and a by-value `ShipConfig`, is fixed, so it took a block form, its counts, its storage and its projection asserts. The rule is categorical now, because the entry can look perfectly fixed. And the reason a table has no block form NAMES THE EDGE THE WALK FOUND, a pointer, a map, or the member that reaches one, instead of the hardcoded sentence about a pointer, which was emitted verbatim over a table whose only variable edge was a map. THE TWO PROJECTIONS. A generated entry is ANONYMOUS in both (§18.1, §20.2): its record line carries the holder's wire id and the map field's wire id joined by a dot, in place of a name, and both projections SORT over that text. The entry's generated name is derived from the field's source spelling, so a `was` rename moved a line, moved the record order and invalidated every cooked file, under an edit that moves no byte. A test pins that the rename now moves neither the projection nor the build version. The map field's line is an array line: `kind=14`, `array=map`, `elem=` the generated entry's own storage size, which is the pitch its entries lie at and what `elem=` means on every other array line this projection writes, and no `bound=`, because a map declares no extent. The KEY's kind and capacity ride on the entry's own `key` line, which is where a key edit moves the id. THE BASELINE gains the map shape token and the key's two facts beside it, and the two policy rows that judge them. A key kind is fixed, because a key arriving under a kind the reader does not declare resets the whole map to empty; a key bound is an extent, because an entry whose key does not fit is skipped whole and counted. The `[..N]Pair` to `map[K]V` edit is one WARN with the page's reason, and it is one finding rather than four: the tokens the construct owns describe the same edit, so judging them beside the shape would say it three times and say it harsher. Two new judged tokens bump the baseline rendering version to 5, and the two committed baselines are regenerated with their history intact. THE COOK PROJECTION'S FORM VERSION moves to 2, because this rendering emits tokens the last one did not. Every unit's build version moves with it, map-free ones included, which is what a form version is for. §20.2's worked number, compiler's pin, docs/USAGE.md's printed number, the build-version goldens, the generated headers' BuildVersion constants and every cooked conformance artifact are re-pinned in this commit. THE ENTRY IS NOT A ROOT. §2.8 makes it the one exception to §7's "a root is any table": it is reached only through the map that generates it, so the C++ reference emits it no Open, no Cook, no Save and no Load, and its walk, its layout and its cook body are the whole of what it carries. §11's Maps list gains the two keys the checker already refuses and the page did not name: a 128-bit integer and a fixed-point key. The map slot's count is an int32 like every companion, and the IR says so. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
§2.8 is the maps design, 654 lines, and this PR is the whole of it in prose: no code, no goldens. It states the construct as present fact so an implementation can be built from it and held to it.
What the page states
A map is a lookup the runtime provides over entries the wire carries. On the wire, in a region and in a cook it is an array of one generated
{ key, value }table held in ascending key order, riding on kind14over kind13. The wire spends no kind. The section states the spelling and the two spellings it refuses, the key set (string(N)and the integer kinds) with every other key refused by name and its reason, the total order, the unbounded count, the value set, and the map as a by-value edge of §3.1's one declaration-order walk.The entry. Its name and its casing (
<Table><Field>Entry,by_idonFleetgivingFleetByIdEntry), the nested form (<OuterEntry>ValueEntry), the file that declares it and where in that file, its two constant field ids at both wire widths, its wire shape, and the fact that it is the one exception to "a root is any table". It claims §11's suffix set as every closure member does.The reader, rule by rule. The key is read before the slot is chosen, by a scan of the entry's field headers, so field order inside a body stays non-contractual. Ascending, equal and descending each say what happens to the slot, the counters and the parent. Keys never clamp: an entry whose key does not fit is dropped and counted
clamped, one per entry, and the order check compares the wire keys of the entries that land. The key kind is the reader's declaration, and at the first entry that disagrees the map reads empty, onekind_mismatchis counted for the map, and the rest of the map is skipped by itsL. One report per wire, so the region load andLoadBuildernever disagree.The rest. The text form and its integer-key rule, the cook and
Find, the absent block form, the memory layout down to the sixteen-byte slot and the pre-order placement of entry arrays inside the node's extent,LoadMeasure's term and its refusal, the optional runtime index and why its hash is not a cross-port contract, the builder's segments, growth and deletes, the cost model, the negative controls, the C++ surface, why the kind stays unspent and what that costs, and the row-by-row comparison with Protocol Buffers and FlatBuffers.What this PR changes
It applies the rulings on a cold read of the previous revision. The read found four rules a port could not derive, two sentences that contradicted the rest of the standard, and a control list that named no corpus row.
The rules the page did not carry:
kind_mismatchfor the map, the rest skipped by the map'sL, and events counted inside earlier entries stand. A value field of the wrong kind stays the entry's ordinary per-field event.LoadMeasure. The term isN x sizeof( Entry )rounded up toalignof( Entry ), at every depth. A wire it refuses answers the-1every measure's refusal answers (§7.6). §4.2's EXACT claim is scoped to a read that reports nothing, and its bound is restated from an entry rather than a record, at six wire bytes.wasrename moves no line. §20.1's closed table gains the map rows, §20.2's grammar gainsarray=mapand the entry'srecordline, and §18.1's shape list gains the map with the key's kind and capacity.Entry,Insert,Find,Erase,Each,IndexMeasure,Index,IndexFind) and the two runtime types (TableMap,TableMapIndex).int32like every companion, and §2.2's extent cap is the cap, at both wire widths.-0is zero, and a malformed key stops the read where §16.1 stops it.Findonmap[K]*Tanswers what a pointer field's accessor answers.Insertanswers NULL for a key that does not fit and for an arena that cannot grow alike, and NULL means not inserted.CookandLock, the refusal §7.6 gives a pointer there.The contradictions:
cook-checkreads containment, alignment, fit and no overlap, not the offset the layout rule computes, so §7's independence sentence stands unchanged.[..N]Pairedit is not silent and safe. The bytes are identical, the read gains the order check, and a wire whose pairs were not ascending reads short, so the baseline warns.The #435 seam. The wire widths are marked as the wire as it stands, with schema#435's beside them: ids become references,
LandNbecome canonical LEB128, and the terminator becomes the zero reference. The cost table's wire rows say the same.The tests. Every negative control names the corpus row or instance that meets it and the one instrument that goes red. Five are added: the walk-order pin, the parent-continues half of the descending rule, one
kind_mismatchwhen the disagreeing entry is a later one,LoadMeasureover a map of maps, andcook-check's entry-array check. The one that was data rather than a control is gone, as is the one that stood on the deleted tool path.The prose. The status paragraph, THE SEQUENCING, the owner quotations, the history and the plans are gone. Every twice-stated fact is stated once and cross-referenced. No gate name the page does not define, and no "reds" as a verb.
VERSIONING.md rides this PR for the two facts it owes: the map row in the three-frames table, and the read report paragraph naming the wire event that raises
duplicate.What the implementation PRs owe
The page is now ahead of the tree in four places, each deliberate and each a line #487 or the codec PR closes:
schema build-version --factsemitskind=0with no tokens for a map field today. The page stateskind=14,elem=13andarray=map.record FleetShipsEntryandtable FleetShipsEntrytoday. The page states the holder-id plus field-id key, in both.schema-tables-baseline 5;internal/baseline's constant is4on main, and the map lines are what moves it.<Table><Field>Entryand nothing else, and with the C++ refusal lifted the generator gives the entry the full table surface. The page claims the eight and the two runtime types, and states that an entry gets noOpen,Cook,SaveorLoad.The cook projection's own form version is not bumped here, because §20.2's worked example is pinned against the compiler by
compiler/tables_test.go. The PR that emits the map tokens bumps it and re-pins that number in the same change.Held by
go test ./...andmake checkare green. The page is prose, so what holds every sentence is the implementation PR built from it.🤖 Generated with Claude Code