Repository navigation
Dialect authoring: carry the complete original inventory by digest and page declarations through the read port (#243) - #250
Conversation
…clarations (#243) The complete original declaration inventory no longer travels inline in the read snapshot, candidate, checkpoints and proposal. They carry a bounded index instead: per original revision, each ordered field's name and the SHA-256 of its exact declaration bytes, plus a digest over the canonical index. The declarations arrive through the read port's paged member, bound to the collection revision and inventory digest, and every declaration is checked against its indexed digest and order before use. - New bounds beside the existing ones: index 2 MiB of canonical JSON, pages of at most 1,000 declarations and 1 MiB. Existing bounds unchanged. - read_dialect shows an inventory summary and pages declarations with cursor/nextCursor; propose re-pages the inventory; the currentness read after preview must show the candidate's inventory digest before retain. - Checkpoints and proposals are version 2 with researchIndex; v0.11.0 version-1 records with inline researchDeclarations still read. - ADR-0028, design section on paging, paging vectors, the issue's 150 x 30 x 1,000-byte reproduction in both languages, mutation rows. Closes #243 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: kikashy <35789537+kikashy@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: kikashy <35789537+kikashy@users.noreply.github.com>
…page (#243) Review of record F1: one refusal test per echoed member (cursor, id, packKey) in Go and TypeScript, with mutation rows. F4: TypeScript copies the host's page before checking it and uses only the copy, so an accessor cannot change declaration bytes after the checks; a test pins it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: kikashy <35789537+kikashy@users.noreply.github.com>
|
Carry needed from base commit 3e0662a. |
Clean-room review record: agent PR #250 (issue #243)Re-read at First round, at
Method
Probes (head results; Go and TypeScript identical except where marked)
The canonical-byte arithmetic in the ADR holds:
TypeScript measures with On allocation: the page and the index are each canonicalized once, at roughly three times the host's own data, before the count or shape checks run. The snapshot is already bounded at 4 MiB before the index check. A host can make the factory allocate a multiple of a page it returned, but not beyond what it handed over. Mutants
Totals:
Findings
For the release notes, the host-facing break exactly:
The maintainer's decision is honoured. The domain is not narrowed: the index covers every original revision and field in order, and nothing is clipped, dropped or sampled. The limits are not raised: the snapshot, candidate, draft and runtime bounds are unchanged, and the new bounds are additional ones. Not established
Re-read at c71a041
F4 is closed because New exposure: none found.
Review notes in the PR body, checked against this record:
Totals at this head:
|
…ging-243 Conflict: packages/harness/scripts/mutation-rows.json, both sides appended rows at the end; kept both groups (agent#242 rows, then agent#243 rows). scripts/parity.sh merged cleanly with both new_files entries. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: kikashy <35789537+kikashy@users.noreply.github.com>
|
🎉 Thank you for your contribution to Judgment Pack! If you’d like another task, choose a path that interests you: |
Carries #250 (dialect inventory paging). mutation-rows.json keeps main's agent#243 rows, then agent#223's; record shapes, the Go contract types and the event reference are regenerated by their generators. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: kikashy <35789537+kikashy@users.noreply.github.com>
…nded for every accepted collection (#252) (#256) * Dialect authoring: a two-level inventory index whose top level is bounded for every accepted collection (#252) The #250 one-level index was checked whole before any page was read, so an accepted Desk collection (450 revisions x 30 fields with 64-byte names) had a 2,180,240-byte index and was refused at the 2 MiB cap. The snapshot, candidate, draft checkpoints, preview and proposal now carry a top index: per original revision its field count and the SHA-256 and canonical byte length of its revision field index, plus the whole-inventory digest. Each revision field index (ordered names and declaration digests) is read through the read port's new readFieldIndex / ReadFieldIndex member and checked against its top entry; declarations are paged and checked as before. Bound proof (ADR-0028 amendment, a Python arithmetic test, and paging.json bounds rows driven in both languages): every top index the shape admits is at most 1,089,098 bytes, a Desk collection's at most 284,098; a Desk revision field index is at most 4,956 bytes and an unescaped 1,000-field one 255,186. Every envelope cap is unchanged. The version-2 record shape of #243 is in no release and changes in place; version-1 records still read. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: kikashy <35789537+kikashy@users.noreply.github.com> * Dialect inventory: pin the field index length check and the revision limit; one blank set in both languages (#252) Review of record F1: a paging case refuses a field index whose canonical length differs from its top entry while its digest matches, and a bounds row refuses 1,001 revisions inside the byte cap. Two mutation rows (agent#252), Go twins applied by hand. F2: blank text is one explicit code point set in TypeScript and Go, the union of String.prototype.trim and strings.TrimSpace, so labels of only U+0085 or only U+FEFF are refused in both; bounds rows carry both cases and an accepted label that contains them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: kikashy <35789537+kikashy@users.noreply.github.com> --------- Signed-off-by: kikashy <35789537+kikashy@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Closes #243. Milestone v0.12.0.
What was wrong
v0.11.0 carried the complete original declaration inventory inline in the read snapshot and in every candidate, checkpoint and proposal, each bounded at 4 MiB. A reachable, accepted Desk collection (150 retained original revisions, 30 text fields each, distinct 1,000-byte descriptions) has a 4,947,643-byte inventory, so the factory refused it at the snapshot bound before authoring began.
The contract now (maintainer decision: declarations by digest, paged reads through the read port)
researchIndex: per original revision in order, each ordered field as{name, digest}(sha256:<hex>of the exactfieldJsonbytes, the repository's existing digest form), plusdigest, the SHA-256 of the canonical JSON ofrevisions. Nothing is dropped, sampled or reordered; unavailable staysnull. Host helpers:dialectResearchIndex/DialectResearchIndexOf.readDeclarations(request, signal)/ReadDeclarations(ctx, request), the read port's paged member. A request namesid,packKey, the bound collectionrevision,inventoryDigest,cursor(position in index order) andlimit. Every page is checked before use. These refuse in the existing tool-input style: another revision, inventory, id, pack or cursor; an empty page or a declaration out of order (missing declaration); a digest mismatch; a page over its byte or declaration bound; a declaration that is not the named field's. An index whose digest differs from its entries, a malformed index, or one over its bound refuses at the read. A non-empty index without the paged port refuses. No other access is added. Host consumers (preview, review) read declarations withreadDialectDeclarations/ReadDialectDeclarations, which apply the same checks.retain.read_dialectpages the inventory once and showsresearchInventory(digest, declaration count, per-revision field count or null). Its schema gains optionalcursor(integer 0..1,000,000). Withcursorit returns one checked page andnextCursor. Its description and guidance say so.propose_dialect's schema is unchanged.Bounds (existing ones unchanged)
DialectIndexBytes/indexBytesDialectPageBytes/pageBytesDialectPageDeclarations/pageDeclarationsVersioning
researchIndex, neverresearchDeclarations.dialect-draft.jsonkeeps their shape and adds a reader rule: version 2 requiresresearchIndexand forbidsresearchDeclarations, and version 1 forbidsresearchIndex.checkpoint.versionis nowenum [1, 2]. The new$defsareresearchIndex,indexRevisionandindexField, and the new candidate member isresearchIndex.researchDeclarationsas an optional, read-only member for version-1 records.DialectSnapshot.ResearchDeclarationsis replaced byResearchIndexplus theReadDeclarationsport. A TypeScript snapshot that still carries inlineresearchDeclarationsis refused with that named reason.dialect-authoring.jsonaddsread.cursorand the port shapespageRequest,declarationandpage.Files
go/context/dialects.go, newgo/context/dialects_inventory_test.go, updated dialect tests,go/certification/scenarios_dialects.go(index and pager in the scenario host), regeneratedgo/contract/contract_gen.goandrecord_shapes.json, anddialects_shapes_test.go(14 inspection checkpoints).packages/harness/dialects.ts, newdialects-inventory.test.ts,testing/dialects.ts(the test host serves an index and byte-bounded pages), updated dialect tests,contract/record-shapes.json, andscripts/mutation-rows.json.contract/README.mdrows, new vectorscontract/vectors/dialect-authoring/paging.json, new witnesses ininputs.json(cursor read, page request, page) andretention.json(two version-2 checkpoints),authoring.jsonexpectedFingerprint(recomputed outside the package; the candidate now carries the index), andtests/test_dialect_authoring_contract.py.docs/adr/0028-dialect-inventory-by-digest.md, anddocs/design/dialect-authoring.mdwith a new section "Paging original declarations (Dialect factory bounds exclude accepted Desk collections with complete original inventories #243)" for hosts that implement the read port. No earlier ADR owned dialect authoring; its contract lived only in the design document, so ADR-0028 is the first record and records this amendment.Vectors and tests
paging.jsonis handwritten; its digests come from SHA-256 outside the package. Both languages drive every case:retain;TestDialectInventoryDeskDomainReproduction(Go) and the TypeScript test "reproduces the 150 x 30 x 1,000-byte Desk domain …" build 150 revisions x 30 fields x distinct 1,000-byte descriptions synthetically. The inline inventory exceeds both 4 MiB bounds. Onmainthe same domain refuses withDialect authoring: the read snapshot exceeds its byte limit.(run against an export oforigin/main). Here it is read, paged twice (9,000 declarations), proposed and retained. The snapshot, candidate, draft and proposal stay within their bounds, every served page stays within the page bounds, and the paged reader recovers the exact inventory.Safeguards and mutants
Each was removed once in a scratch copy, and its test failed at the intended assertion. TypeScript rows are in
packages/harness/scripts/mutation-rows.json, originagent#243, grouped at the end. Go twins were run by hand.Three existing rows changed their
findtext to the moved code: prior exact read, complete-original-inventory and strict-original-declaration. All three are caught again. The Go twin of complete-original-inventory needs the retain binding off to reach its assertion, because the new binding catches it first.Review notes
Follow-ups after the clean room on 968ed6a:
6e512e7declares the new test file inscripts/parity.sh.c71a041fixes F1 and F4:Host-facing break, for the release notes:
DialectSnapshot.ResearchDeclarationsis removed.ResearchIndex *DialectResearchIndex, built withDialectResearchIndexOf.DialectAuthoringPorts.ReadDeclarationsis required whenever the index names a declaration.DialectCandidategainsResearchIndex. ItsResearchDeclarationsisomitemptyand used only for version 1.researchDeclarationssilently drops it, so the inventory reads as unavailable (F7).researchDeclarationsis refused by name: "the read snapshot carries an inline researchDeclarations inventory; supply researchIndex and readDeclarations pages instead."researchIndex(fromdialectResearchIndex) andports.readDeclarations.versiontype is1|2.checkRecordaccept them, as they already do for the existingstageconditional.DialectCandidateis not byte-faithful (F6). It addsresearchIndex: nulland dropsresearchDeclarations(nulland[]alike). No package path re-encodes version-1 records, and the generated contract codec stays byte-preserving.Checks
Candidate: head
968ed6a301f80fd313f87f77c89999c85f1df058with no uncommitted diff. Scope:jpdev check --changed origin/mainselected all 24 steps. Local toolchains were Go 1.26.5 (the manifest names 1.26.10, which is not installed) and Node 22.Self-checks:
CI owns the exact-head run and the push-to-main mutation table.
🤖 Generated with Claude Code