Lars, Rouiada, Sankalp, all,

+1 to naming RFC 8785 for every digest over a JSON value, with jcs-sha256
as the declared identifier. Rouiada's integer cases are the gap the
paragraph has to close, and the rule that closes them is already on record
in the AI KR comparison-semantics section: a value under such a digest
carries integers only within ±(2^53−1), and anything larger travels as a
string. Proposed sentence: "A JSON value under a jcs-sha256 digest MUST NOT
contain a number outside the range −(2^53−1) to 2^53−1 or a non-integer
number; such values are carried as strings. A reader rejects a report whose
digested value violates this, under W3C-R-020, naming the cause." That
makes Rouiada's two colliding pairs unrepresentable rather than ambiguous,
and leaves -0 decided by RFC 8785 as Lars showed.

Kenne

On Fri, Oct 9, 2026 at 12:07 PM Rouiada Abbas <
hello@vacationrentalprotocol.com> wrote:

> Sankalp, all,
>
> Here are the leaf objects for the encoding pair offered in 0026: one for
> each case you listed, plus U+20AC in a value and one object with all
> five. There is no float case, since a float in a check leaf is refused
> (0026). Roots are not included, and the objects are bare, not wrapped in
> v0.1's leaf record; the reason for both is below. +1 to naming RFC 8785
> for every digest taken over a JSON object and keeping the corpus digest
> over raw file bytes, with one condition on integers, given under "What
> the cases show".
>
> Encodings. "RFC 8785" is RFC 8785. "Readers" is the readers' encoding as
> this thread describes it: compact, member names sorted by code point,
> U+007F and every non-ASCII character written as \uXXXX (a
> supplementary-plane character as its surrogate pair), integers digit for
> digit. The readers part on -0, as read in source in 0026: the Python
> reader writes 0, the Go reader writes -0. The Python reader and Go
> reader rows below are computed here from that description, each with its
> reader's -0 rule; they are not output of the readers' code. In
> results.json and the README the labels are A.cpython (Python reader),
> A.go (Go reader) and B (RFC 8785). Each case below gives its input, then
> for each label the canonical bytes in hex and the SHA-256 over exactly
> those bytes. Hex longer than 64 digits is wrapped at 64 digits; join the
> lines. The input of case 6 is one line, wrapped here after a comma.
>
> 1. U+007F in a string value
>    input:
>    {"a": "\u007f"}
>    readers, bytes:
>    7b2261223a225c7530303766227d
>    readers, sha256:
>    a4af0e87f2a880833c6eb0b57292a24fdf6f31a9042788e7a74204170c4d3c25
>    RFC 8785, bytes:
>    7b2261223a227f227d
>    RFC 8785, sha256:
>    599df87d312c1247f328cf89d9fbd469522aa6424298636df84ef7a4985dd6bb
>
> 2. -0
>    input:
>    {"a": -0}
>    Python reader, bytes:
>    7b2261223a307d
>    Python reader, sha256:
>    45b619e97b5d9b029af4522e9ffb02fa99ff2bf226c82ee22a7cc10269a557e8
>    Go reader, bytes:
>    7b2261223a2d307d
>    Go reader, sha256:
>    dbd681e539ad171ed90bfe0b80b788200b28a669b886b868605c53fb1ee9a962
>    RFC 8785, bytes:
>    7b2261223a307d
>    RFC 8785, sha256:
>    45b619e97b5d9b029af4522e9ffb02fa99ff2bf226c82ee22a7cc10269a557e8
>
> 3. 1000000000000000000000
>    input:
>    {"a": 1000000000000000000000}
>    readers, bytes:
>    7b2261223a313030303030303030303030303030303030303030307d
>    readers, sha256:
>    95ab89bf89f786b088f20f089413c4b96da8011067eabd84dd948ce6194e1491
>    RFC 8785, bytes:
>    7b2261223a31652b32317d
>    RFC 8785, sha256:
>    a18fbc0bcef4f91fedea4a6ff70089101462846a93a65795324a14b10cb5c4d9
>
> 4. U+1F600 and U+FB33 as member names (code point and UTF-16 order part)
>    input:
>    {"\ufb33": "U+FB33", "\ud83d\ude00": "U+1F600"}
>    readers, bytes:
>    7b225c7566623333223a22552b46423333222c225c75643833645c7564653030
>    223a22552b3146363030227d
>    readers, sha256:
>    c1d16b59a8212306fcad3da4eeb0db423a8434d9ea9001f30f5f809b8f7d2053
>    RFC 8785, bytes:
>    7b22f09f9880223a22552b3146363030222c22efacb3223a22552b4642333322
>    7d
>    RFC 8785, sha256:
>    adf6f92d367e4ffcd380bbaa4faa02e5290394df4e502fd4085b5f1e4092c2de
>
> 5. U+20AC in a string value
>    input:
>    {"a": "\u20ac"}
>    readers, bytes:
>    7b2261223a225c7532306163227d
>    readers, sha256:
>    d0cc495e9390699629e536647a193fefa7f5c785e916bcc3157975f7a04070f9
>    RFC 8785, bytes:
>    7b2261223a22e282ac227d
>    RFC 8785, sha256:
>    db8566e7dc218a6795f689fe26667214b263a2443d9966d00742cbd38019c33e
>
> 6. all five in one object
>    input:
>    {"\ufb33": "\u20ac", "z": 1000000000000000000000,
>     "\ud83d\ude00": "\u007f", "a": -0}
>    Python reader, bytes:
>    7b2261223a302c227a223a313030303030303030303030303030303030303030
>    302c225c7566623333223a225c7532306163222c225c75643833645c75646530
>    30223a225c7530303766227d
>    Python reader, sha256:
>    e4a64ce790457b1c64a6f64c229272bb92e2b6cc60218be8dfc97fa6625e2340
>    Go reader, bytes:
>    7b2261223a2d302c227a223a3130303030303030303030303030303030303030
>    30302c225c7566623333223a225c7532306163222c225c75643833645c756465
>    3030223a225c7530303766227d
>    Go reader, sha256:
>    06a88f39d1cc912243f12b2f6329b87c6f5e244c98e7d32c75c61967816b436b
>    RFC 8785, bytes:
>    7b2261223a302c227a223a31652b32312c22f09f9880223a227f222c22efacb3
>    223a22e282ac227d
>    RFC 8785, sha256:
>    7a93a85220e0d6a6e643b5481fc43083a3fe33599c9f7fe6eff70f2983a6beb4
>
> What the cases show:
>
> - -0 parts only the Go reader from RFC 8785. The Python reader and RFC
>   8785 both write 0 (RFC 8785 Appendix B), so both give
>   45b619e97b5d9b029af4522e9ffb02fa99ff2bf226c82ee22a7cc10269a557e8. A -0
>   member does not tell the two encodings apart for the Python reader.
>   Every other case parts the readers from RFC 8785.
>
> - Under RFC 8785 a number is its IEEE 754 binary64 value, not its token
>   (section 3.1: number data MUST be expressible as binary64). A parser
>   that reads into binary64, as ECMAScript's and both programs here do,
>   rounds a token that is not exactly representable, so two different
>   leaves can share a digest. {"a":1000000000000000000000} and
>   {"a":1000000000000000000001} both come out as {"a":1e+21}, sha256
>   a18fbc0bcef4f91fedea4a6ff70089101462846a93a65795324a14b10cb5c4d9.
>   {"a":9007199254740992} and {"a":9007199254740993} both come out as
>   {"a":9007199254740992}, sha256
>   65c07d758377f303542fde97a8fe78f29a66c1e062b8f80fed3106a6d106d88b. The
>   readers' encoding keeps each pair apart. RFC 7493 section 2.2 says an
>   I-JSON sender cannot expect a receiver to treat an integer whose
>   absolute value is greater than 9007199254740991 as exact, and RFC 8785
>   section 3.1 recommends strings for longer integers (Appendix D). So if
>   the paragraph names RFC 8785, it also needs to say which integers an
>   object under such a digest may carry, a check leaf or an identifier
>   preimage. The 1e+21 member is itself beyond that limit. Both programs
>   compute these rows; they are in results.json under integer_rounding.
>
> - This code was written without the readers' source, so lowercase hex in
>   the readers' \uXXXX is assumed; it is what CPython's json module
>   writes. If the readers write uppercase, the reader bytes of cases 1,
>   4, 5 and 6 change.
>
> Why no roots, and why bare objects. This code was written without the
> v0.1 text, the vectors or the generator. As cited in 0025, section 3.1
> of the v0.1 text has a report declare its tree shape from a closed,
> versioned set of tree-construction and hash identifiers (lines 229-231,
> 240-241), and O3 (lines 774-775) records that the list has not yet said
> what "flat" denotes in the text's own terms and that until then a member
> of that set is defined by its vector pair. So this code can give the
> objects above, but not v0.1's leaf record around them, and not a root
> without guessing. Once the text pins the tree (among other things the
> leaf preimage, node hashing, the leaf order, the rule for an odd leaf,
> the hash identifier and whether it enters the hashed bytes, and the form
> of the root), I'll post the roots for each row label (Python reader, Go
> reader, RFC 8785) without changing a byte of these objects.
>
> The code is two implementations, Python and Go, standard library only,
> written from RFC 8785 and the rules it refers to (ECMA-262 for numbers,
> RFC 8259 and I-JSON for parsing) and the readers' encoding as this
> thread describes it. They agree byte for byte, and both pass RFC 8785
> Appendix B and the examples in sections 3.2.3 and 3.2.4. One AI-assisted
> author wrote both without opening the generator or its vectors, so they
> are independent of the generator but not of each other. A third
> computation, by a different AI model on five inputs of its own, agrees
> byte for byte with both programs; its stated values and the comparison
> script are included. Code, tests and results.json are attached as
> jcs-enc-vectors.tar.gz (Apache-2.0), sha256
> 42584aa6e9a37fae6ffa3123b1632b6ad3427a6d443514c56cb6d5b66f22ebb4.
>
> Rouiada
>
> Prepared with AI assistance.
>
> > På 2026-10-09 17:24 CEST skrev Sankalp Gilda <sankalp.gilda@gmail.com>:
> >
> >
> > Lars, Rouiada, Guigui, Evgenii, all,
> >
> > Lars -- thank you for both runs and for your correction in 0025. Two RFC
> 8785 canonicalisers agreeing says nothing about the report level, so you're
> right. Nicolás's question in September (
> https://lists.w3.org/Archives/Public/public-agent-conformance/2026Sep/0089.html),
> whether anyone independent of me has checked the reader, is still open.
> Answering it needs a v0.1 reader that shares no code with mine, and I'd
> welcome one at any release. Both keys do sit inside the repository they
> vouch for, so a verifier has nothing outside it to start from. I'll put the
> fingerprint of release/cosign.pub, the key that signs CORPUS-DIGESTS.txt in
> each release (
> https://github.com/probityai/agent-evidence-vectors/releases/tag/v0.17.4),
> into the text of the reporting-format deliverable, and then a verifier
> starting from the group's document has an anchor outside the repository.
> >
> > On the digest encoding, I'd name RFC 8785 for every digest taken over a
> JSON object and keep the corpus digest as SHA-256 over the raw file bytes.
> Rouiada, yes please, post the leaves you offered in 0026. I'll add the
> encoding pair to vectors-w3c-report, the 235-member report corpus that
> Lars's 165-member selection came from, in the next agent-evidence-vectors
> release with every case you listed: U+007F, -0, 1e+21 against the digit
> spelling, and a supplementary-plane member name. I'll post its corpusDigest
> here when it's out.
> >
> > Guigui, Evgenii, I agree on the four members excluded only under
> W3C-R-022. They should be their own class while the rule is proposed,
> counted outside the 83 rejects and 82 accepts, so the headline numbers rest
> on agreed rules alone. excluded-under-proposed-rule works for me as the
> name.
> >
> > For section 10 in v0.2 I'd propose that a conforming report says what it
> was judged against:
> >
> >  A conformance report MUST carry the corpus release, the corpusDigest of
> the corpus it was judged against, and the identifier of every member it
> judged. A report whose evidence does not hold is void, with the cause
> evidence-does-not-hold. A member excluded under a proposed rule MUST be
> reported as excluded-under-proposed-rule. A report missing any of these
> does not claim conformance.
> >
> > Julian, as chair,could you confirm me as co-editor of the
> reporting-format deliverable, the seat Evgenii offered on this thread, and
> as editor of its test suite? I accepted both in
> https://lists.w3.org/Archives/Public/public-agent-conformance/2026Oct/0022.html
> .
> >
> >
> >
> > Best,
> > Sankalp Gilda, Ph.D.
