[SCITT] Re: New draft: The Coverage Attestation Profile (draft-hillier-coverage-attestation-00), and a request to break it

Anton Sokolov <anton.sokolov@tyche.institute> Tue, 25 August 2026 06:12 UTC

Return-Path: <anton.sokolov@tyche.institute>
X-Original-To: scitt@mail2.ietf.org
Delivered-To: scitt@mail2.ietf.org
Received: from localhost (localhost [127.0.0.1]) by mail2.ietf.org (Postfix) with ESMTP id A9F6712EE1453 for <scitt@mail2.ietf.org>; Mon, 24 Aug 2026 23:12:45 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ietf.org; s=ietf1; t=1787638365; bh=B0sqqrdqDO+96C2eofl4yR2WKgzqEizksCIFnFeCtaA=; h=References:In-Reply-To:From:Date:Subject:To:Cc; b=px0Omza6s7FfZ8PwjiOfWDYAmUS+vtxjT+bq7hqd9EqNbpRH6UJz+lq6Y3A2hNB3U a+K4e4CZBGds9kGKzntmA/MDdCuBQeUpVVyd7naUl8PrGe/jWMZwj94ohaS2c3Wn/2 9nyPo9TBMUKFlKZD1fvuEtFzYwtey7wD2UruAAec=
X-Virus-Scanned: amavisd-new at ietf.org
X-Spam-Flag: NO
X-Spam-Score: -2.1
X-Spam-Level:
X-Spam-Status: No, score=-2.1 tagged_above=-999 required=5 tests=[BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001] autolearn=unavailable autolearn_force=no
Authentication-Results: mail2.ietf.org (amavisd-new); dkim=pass (2048-bit key) header.d=tyche.institute
Received: from mail2.ietf.org ([166.84.6.31]) by localhost (mail2.ietf.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id fJJKGn6DYahM for <scitt@mail2.ietf.org>; Mon, 24 Aug 2026 23:12:43 -0700 (PDT)
Received: from mail-yx1-xb133.google.com (mail-yx1-xb133.google.com [IPv6:2607:f8b0:4864:20::b133]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits) key-exchange X25519 server-signature ECDSA (P-256) server-digest SHA256) (No client certificate requested) by mail2.ietf.org (Postfix) with ESMTPS id 3D2C012EE1426 for <scitt@ietf.org>; Mon, 24 Aug 2026 23:12:43 -0700 (PDT)
Received: by mail-yx1-xb133.google.com with SMTP id 956f58d0204a3-66c7127a73dso4995079d50.2 for <scitt@ietf.org>; Mon, 24 Aug 2026 23:12:43 -0700 (PDT)
ARC-Seal: i=1; a=rsa-sha256; t=1787638356; cv=none; d=google.com; s=arc-20260327; b=h+i7bphRXom2AAL1EkNoJ79bjfbW/zG8IZbtOCLUPy9qNeBulQj57HnB3MoJKTIrzS gZaXrWZfQEEXIAHuwLR26A73nTrALD/rUMpeaAeZ72q6h59CqzrfPcgHjT8HlorE2tz1 M9Nrxs2uugK3YYsmV1YiQMDa8+1XE6kEEcbN6ClYp6joB8BF0QW1XdgnpkEBMD4q9ZzE zSVIyS4UV/L7PMvfMOeasozYZNd5trSq8QhJwm4wzOZt1XAc6VccelcAzEgTaYWcoqFH MxdOqqGAfIBr5zLbTZlff+toe059mQ1ReJX8aVH9YJaeLHNlswjqoEusWglXelDX2P2d zhgg==
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20260327; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:dkim-signature; bh=l10wiQwwwsoeeAlAd4TP6sDMO1/5JYPu8M56G7l3O4o=; fh=Mcjxix6OMFQAaNDdF3wMA38/UaLU+bSm/EaWzaL1nqU=; b=HjwdRntgMzbBgETtmh1WNe958X0fkNNN1iLsDaQW889G/bXn+R0hUlmsHULFCzsAcp MGT4gbuJ+Omd0L98q/rSBNVgUSo6XnGKm20HPi2VKxa11ionJBDJaH4R8+nPqJTvgYHD WH+x5hiw6dDmg5OYwmFv9uB8UYVtRNeG5BFhzcxtD19+BGhEbZbTVLvzjP7KmvAjZDcN 14HaicUhAWjfSS0H1Ix/o/q0zyD3enXrUq9LhadhUQsi/oSe0+wINLpmheNToiJ175lQ yqZVGTeSBxt9tskNSljmNYIZudaHBFne/2NqPse7JiJ+ZX9tvujIQ6Tv3KqxH9p31Bhn cc6Q==; darn=ietf.org
ARC-Authentication-Results: i=1; mx.google.com; arc=none
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tyche.institute; s=google; t=1787638356; x=1788243156; darn=ietf.org; h=content-transfer-encoding:content-type:cc:to:subject:message-id :date:from:in-reply-to:references:mime-version:from:to:cc:subject :date:message-id:reply-to:content-type; bh=l10wiQwwwsoeeAlAd4TP6sDMO1/5JYPu8M56G7l3O4o=; b=b4hdXouz8tGiXftQgJKM7lDl+tp9X7ypRF7ehKHYepwlZwer4ne+69UaZtgOoHqVPr /Obi7v7cUchTF99sVNYvpzwmxjLUi7xjviLF4Cx77davsFEtbOulCHO/hla0QDWwePQZ fD25ya0AyfFgjDunEseD7mxnky0z9JHdK4PmVmXfeDWYwDwmi2DfjQWpNxVZJSvzxA1s 3dh2NOknzyXmPRRW1ZsWdwoqLsHF3okVRVMhVvGCAS6folr5LzAgly73qZ3+aIGPYcfK HCmaQGX7k3eyKLVj81MqWxLt5he+nCw9GcRpOXquLRKYtPN2E4Suspp/aR6WmwSCDxBu dO9A==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1787638356; x=1788243156; h=content-transfer-encoding:content-type:cc:to:subject:message-id :date:from:in-reply-to:references:mime-version:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=l10wiQwwwsoeeAlAd4TP6sDMO1/5JYPu8M56G7l3O4o=; b=DcmmIhgjEFLJdv1sHrqplRwREFc5Q1mlQOTK/kA3f2W8czimEA9aH6y/2ZfXUdY6Wf iGRI84VaN3AWKECbq7ovtCBpnutloi8WHxgttEF/Dd3rd/B/RkOiPXkwBTdfjXSZy52O QRrq0QUCsXNDX1sYd9+hw3hwyI7lGxFLJuXyaO9LQRjxjP39ksVK7rlgjQciKH0p7uWi KCANdUaEzZwAQiBUojUuJdASEqiHksEItxseDMOv5RBtsI8Hqa68XfgZCgKby1Wu68al 3LE3j62Q8HrSdoqD0A0RYqwe19gN6PIgZx/wS7mXVvVFvIlxeKvUwHGZWwYQJIcyHPCr KX+A==
X-Forwarded-Encrypted: i=1; AHgh+Rret9O+sukOcUFbjpdkvBOJTAA149zEeLFdiMOgSNVIUaV1RSEoLsHLnorhTw7HKX0e776Xbg==@ietf.org
X-Gm-Message-State: AFuF++l0xtUIwL3c02J7uTEY8lzlMUn/WnKiXNjaL5Rc25cVdCpg4Q2Z pPekWy0BPVvmCorcaPsHlDfJN3ZePWJuL8AhZhGgV6mzewuu6lW2VGsBk6qQAs7EI1k1tXlR2M5 hP7C66bGuXqBZ3FwszDQbwkIY9mO2F65eDV+XuhEhr1E=
X-Gm-Gg: AR+sD110t45lv0lejZJgrapRBInaVfMF8WOwq8bbA7GvKl52t0DO73de87Nn8fiNgbr qNHNkg84Mka/KcXXPu1ry3HzWXUq1E4v14bfyFme0a547C0FWva3lF6dyZl/OjmBiwPl21ln7Zj iURT4DFciQfAmkNbGjhdBtjfTIPWrvJ0z0w0dx0mMfwmOQ4SATOH5SCwhfPaD5DtLYwDDpvD0Ep uScNGVEWpRilq0PHQ9ne2X7Qf5TASz+NvCufGX1RhhojUY0f1xlqbrTE70ys2OGEthZHB+Xgzqd K0T8HKmlyf+4g4a3hvn/3/PNFS3uxZcowm8UkN0t1tQVKIlVYHCbBa3TsVdwBrjiXop4SYRxml0 9XX9SSLeGyVscJQ9kU0O72mtRg73MWVpgSBe7bT04DfIfF4YHuLkekcZlrw==
X-Received: by 2002:a05:690e:4846:b0:668:9a6f:3373 with SMTP id 956f58d0204a3-66cf21c0fa2mr5401742d50.27.1787638355651; Mon, 24 Aug 2026 23:12:35 -0700 (PDT)
MIME-Version: 1.0
References: <BYAPR19MB280613FCD91EC0ED03A93970ADA42@BYAPR19MB2806.namprd19.prod.outlook.com> <CALc05oF+y8m9SicMQVj67mTv1gzq2f0Tw0-W0Vne6P6FLJ-rPQ@mail.gmail.com> <BYAPR19MB2806B7556B4AB84F63552AFCADA32@BYAPR19MB2806.namprd19.prod.outlook.com> <-sWoyUfMoJJCl1kSwvG2a6ktystdUVegqxG32dF9SKTmCfjbbhRgzsmcIayE9tLC-gpXhD59c-Fi-7SNyzVY6JnyGAEjdX9B9iu3EeB6SOo=@donttrustverify.pt> <1787598066358546818.1787598066@conarium.dev>
In-Reply-To: <1787598066358546818.1787598066@conarium.dev>
From: Anton Sokolov <anton.sokolov@tyche.institute>
Date: Tue, 25 Aug 2026 09:12:23 +0300
X-Gm-Features: AcwNN1UM04egIz_BNMZ1kKO_GN3asYZeWLQa08Jjl3WDw6w1vheuJ93EOfUnp6g
Message-ID: <CAMkGB8P3p_c+5nNPNTiosKT9jkQMQWKJk0G-3dsePqdT8SYnxg@mail.gmail.com>
To: e.dogru@conarium.dev
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
Message-ID-Hash: CWD43JIL5AFDORK6U6XG2TMS3OQNAMJV
X-Message-ID-Hash: CWD43JIL5AFDORK6U6XG2TMS3OQNAMJV
X-MailFrom: anton.sokolov@tyche.institute
X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header
CC: tiago=40donttrustverify.pt@dmarc.ietf.org, jhillier=40certisyn.com@dmarc.ietf.org, scitt@ietf.org, wdhawkins46@gmail.com, team@emiliaprotocol.ai, hello@vaara.io, playplay2736@gmail.com, Todd.Gibson@t-mobile.com
X-Mailman-Version: 3.3.9rc6
Precedence: list
Subject: [SCITT] Re: New draft: The Coverage Attestation Profile (draft-hillier-coverage-attestation-00), and a request to break it
List-Id: "Supply Chain Integrity, Transparency, and Trust" <scitt.ietf.org>
Archived-At: <https://mailarchive.ietf.org/arch/msg/scitt/_yf_LT-bXeCC_QQdQpcVq7vS_Qk>
List-Archive: <https://mailarchive.ietf.org/arch/browse/scitt>
List-Help: <mailto:scitt-request@ietf.org?subject=help>
List-Owner: <mailto:scitt-owner@ietf.org>
List-Post: <mailto:scitt@ietf.org>
List-Subscribe: <mailto:scitt-join@ietf.org>
List-Unsubscribe: <mailto:scitt-leave@ietf.org>

Joel, all,

Late to this, so I read the thread through before writing and dropped the two
things I had that Emek, Walter and Tiago already have. What is left is one
dimension I could not find anywhere in the thread, and you have already
accepted a version of it one level up.

In ARP, a sweep could be complete over a bracket of ledger sequence numbers
that began after the entries an operator would rather not have examined,
because nothing required a bracket to abut the previous one. You repaired it
by requiring abutment and by disposing any deliberately unexamined range
individually, with a reason the reader can check.

CAP-1 has the same exposure in a weaker form, because a stratum has no bracket
at all.

Coverage in CAP-1 is not dated. as_of appears once, in the list of optional
top-level members in Section 4, and no normative rule refers to it. R4 makes
the denominator's provenance checkable — which catalogue revision, which
enumeration method, or the admission that it was merely declared. Nothing
makes its currency checkable.

Two consequences, and the second is the one I would fix first.

A catalogue basis pins which revision was counted against. It does not pin
when the counting happened relative to that revision. Take two documents
identical byte for byte, both citing catalogue digest D: one produced while D
was in force, one produced a year after the catalogue moved on. Both conform.
No verifier separates them, and the two readers are entitled to different
conclusions. That is the failure Section 1.1 describes, reappearing in the
denominator rather than in the remainder.

The second is inside the vocabulary. Several dispositions are facts about a
moment recorded as facts about a unit. unavailable is defined as "could not
be dispatched at all, for want of a dependency, a licence or a network". A
licence lapses on a date; a network is out for an hour; a dependency is absent
until someone installs it. disabled_by_policy is true of a policy version,
out_of_scope of an authorisation, and authorisations are amended. A CAP-1
document states which unit and which disposition, and not as of when — so a
reader cannot tell a standing property of the unit from the state of the world
on one afternoon. Re-run tomorrow and the same unit is examined, with no
contradiction to detect.

So the profile refuses a remainder that reconciles only by subtraction, and
accepts a denominator that reconciles only by an unstated moment.

That this is not a corner case, I can put a number on. On the EU Trusted Lists
— a catalogue of record in exactly R4's sense, versioned and published — 2,071
of 4,815 trust-service entries, 43 per cent, carry a status transition from
valid to revoked somewhere in their published history. All 26 reachable
member-state lists are affected, at rates from 6 to 81 per cent. Corpus, tool
and per-list provenance hashes:

  https://github.com/tyche-institute/time-travel-evidence-lab
  https://doi.org/10.5281/zenodo.20840168

Those are trust services rather than detector routines and I am not claiming
the populations are alike. The transferable part is narrow: a denominator
drawn from a versioned catalogue of record is not stable, so "counted against
revision D" and "counted at time T" are two different facts, and CAP-1 records
only the first.

The minimal repair, in the draft's own idiom and in the shape you already used
for ARP:

  R9, coverage is dated. Every stratum MUST state the interval over which
  its units were examined. Where basis.kind is catalogue, the cited digest
  MUST be the revision in force throughout that interval; where it was not,
  the stratum MUST be split at the revision boundary.

And then either give as_of normative force or delete it. An optional member
that no rule reads is somewhere for a reader to find comfort the verifier
never checked, which is the failure the draft exists to prevent.

Second, much smaller, and it is Tiago's rather than mine — he listed duplicate
unit identifiers among his smaller findings without developing it. The only
uniqueness requirement in -00 is in R0, on stratum identifiers. Nothing
requires the units inside unexamined to be distinct, so R1 can be satisfied by
listing one unit twice, which leaves one genuinely unaccounted unit outside
the accounting while the arithmetic closes. R1 exists to stop a remainder that
reconciles by subtraction; repetition reconciles it by addition and arrives at
the same place. "Individually accounted" gestures at distinctness, but a
verifier author has to infer it, and with four implementations in this thread
that is exactly the kind of inference two of them will make differently. One
clause in R1 or R2 settles it.

I have not written a verifier against -00, so treat the first item as a
reading of the text and not as a run. If it survives the thread I am glad to
write the interval half up as text for -01.

Anton Sokolov
Tyche Institute MTÜ, Estonia
doctoral researcher, Tallinn University of Technology (from 1 September 2026)

On Mon, Aug 24, 2026 at 10:01 PM <e.dogru@conarium.dev> wrote:
>
> Joel,
>
> Your question, answered by measurement rather than recollection: it was a checkout setting on my side. The stored bytes are fine and the bundle is not wrong.
>
> The setting is core.autocrlf. On this machine it is true at the system level, which is where Git for Windows puts it; I had not set it anywhere myself. With it on, every one of the forty files under cap-1/src differs on disk from its stored blob. NC-01.json is the smallest example:
>
>   stored blob 1303 bytes 31e430d5f67447fe3e3e09c154ecd29c396615f58bfb761b36f1d1a03189ebbf
>   working tree 1360 bytes 82e280734824963097c4edb310b6b5cf1e1d4638d81a86b98a4231b5b3cc23d5
>
> Fifty-seven bytes for fifty-seven lines, one CR each. Cloning the same commit with core.autocrlf=false gives a working tree where all forty files match their blobs exactly.
>
> With that checkout, your class digest reproduces here:
>
>   742509bba744a1b6bf57a057a7769db00d583dbf656648218583a53dcac51254
>
> Fifteen members, manifest.json excluded, paths relative to cap-1/, which is the root Tiago had to use as well. So his reading and mine now agree on the value and on why the other value existed: the construction fixes the bytes and the ordering, but not the reference point of "relative path" - and it does not fix the checkout that produces those bytes in the first place.
>
> The second one is worth a line in the bundle, because it is the same defect one level down. A .gitattributes in the repository, even just `* -text`, would make the stored bytes survive a clone on Windows, so a reader on that platform hashes what you hashed rather than what their Git wrote for them. There is none in the tree at 0980d32. Without it, the artefact built to end this class of ambiguity has a platform-shaped hole in it, and a reader who falls in cannot tell that from a real disagreement. I fell in, and reported it as one.
>
> The bundle digest I still cannot check, and my count of the tree agrees with Tiago's: at 0980d32 there are 52 tracked files, 49 under cap-1/ and 40 under cap-1/src. Neither verify_bundle.py nor mutate_bundle.py is among them. So I cannot derive the forty-two-member set from the published bytes either, and I would rather say that than guess at a composition.
>
> Emek
>
>
> On Mon, Aug 24, 2026 at 8:45 PM Tiago Pinto <tiago=40donttrustverify.pt@dmarc.ietf.org> wrote:
>
> Joel,
>
> You asked whether the bundle clears my reproducibility bar. I wanted to
> answer that by actually rebuilding it rather than by reading the
> description and guessing.
>
> The class digest does reproduce.
>
> >From the public tree at commit 0980d32, I get:
>
> 742509bba744a1b6bf57a057a7769db00d583dbf656648218583a53dcac51254
>
> using the construction you described: lowercase SHA-256, one U+0020, the
> POSIX path, bytewise ordering by the UTF-8 path, U+000A after every line
> including the last, then SHA-256 over the resulting sequence. I used the
> fifteen vectors and excluded manifest.json.
>
> There is one input to that construction that is not fixed by the six
> points as written: the path root.
>
> To obtain 742509..., the paths have to be written as:
>
> src/vectors/NC-01.json
>
> so the effective root is cap-1/.
>
> If I use the same files and the same construction, but write the paths
> relative to cap-1/src/vectors/, the digest changes. That produces the
> ce88ddfc0feaec90... value you attributed to Emek.
>
> Nothing about the file contents or hashing procedure changes between
> those two runs. Only the namespace of the path changes.
>
> So I think the remaining repair is small: make the root part of the
> digest construction itself. Otherwise two readers can follow the stated
> procedure correctly and still hash different byte sequences because
> "relative path" has no fixed reference point.
>
> The bundle digest is where I stop being able to reproduce the object
> from the public bytes I can currently reach.
>
> At 0980d32, cap-1/src contains forty files. The bundle declares
> forty-two members. I looked in Certisyn-Inc/certisyn-drafts across all
> branches and the commit history, and in both archives carried in the
> tree, so if those members are public somewhere else, I have been looking
> in the wrong place and a pointer is enough to close that part of the
> question.
>
> If the difference is verify_bundle.py and mutate_bundle.py, the two
> filenames mentioned in your message, I could not locate either in the
> public tree I used for the reconstruction. If the bundle composition is
> different, then I am reconstructing the membership incorrectly, but that
> leads to the same practical problem: I do not yet have enough
> information to derive the exact forty-two-member set from the published
> material alone.
>
> That distinction matters to me more than the digest algorithm. The class
> digest is reproducible once its root is fixed. For the bundle digest, I
> first need to be able to reconstruct the member set itself.
>
> So my answer is:
>
> The class digest is reproducible. The construction itself clears the bar
> once the path root is made explicit.
>
> The bundle construction may clear it too, but I cannot verify that yet
> because I cannot independently reconstruct the exact member set that was
> hashed.
>
> If you publish the member list, or point me to the public object that
> defines those forty-two members, I can finish that check without making
> assumptions about the composition.
>
> Once that is pinned, I will run the class independently. I will freeze
> and hash my implementation and interpretation notes before the run, then
> report the source, environment, input digests and per-vector results.
>
> Best,
>
> Tiago Pinto
> Independent author and researcher, verifiable trust and AI governance
> https://donttrustverify.pt
>
>
> Em sexta-feira, 21 de agosto de 2026 às 15:07, Joel Hillier <jhillier=40certisyn.com@dmarc.ietf.org> escreveu:
>
> > Hi Walter, Emek, Tiago, Iman,
> >
> > Well, you all took me seriously when I said break it, and inside a day. Thank you. This is the loop working exactly as it should, and it's a far better use of a draft than agreement would have been.
> >
> > Emek has now run both his text-derived verifiers against the published fifteen, and that result is the news, so it goes first. Everything else is conceded below it, and the pinned bundle is at the end.
> >
> > Two readings of my document, run against my own class, agree on nothing.
> >
> > verdicts strict attribution
> > reader A 14/15 9/10
> > reader B 10/15 0/10
> > A vs B disagree on 15 of 15
> >
> > Fifteen for fifteen. Not a divergence on an edge case, a total divergence, and it has one root: the draft doesn't name the members.
> >
> > And the root under the root, which I would not have found by reading either. Emek's finding is that the published schema makes Section 9's MUST unsatisfiable. I checked it against the schema rather than take it on trust, and it reproduces exactly:
> >
> > subject.digest object, required [algorithm, value] states it
> > catalogue_digest string ^[0-9a-f]{32,128}$ cannot
> > withheld_digest string ^[0-9a-f]{32,128}$ cannot
> >
> > Section 9 says a producer "SHOULD use an algorithm that is unbroken at time of production and MUST state which was used." The pattern spans 32 to 128 hex, which is MD5 through SHA-512, so the algorithm isn't recoverable from the value. And both enclosing objects, `basis` and the `unexamined` item, are `additionalProperties: false`, so a producer who wants to comply has nowhere to put the statement. At two of the three sites where R3 and R4 rely on it, the schema forbids compliance with the draft's own MUST.
> >
> > That isn't a style inconsistency between two shapes. It's a normative requirement that cannot be met, and it's the root of the string-versus-object split Emek measured yesterday as eight disagreements in twenty. The first shape is the one to keep. `{algorithm, value}` goes to the other two, because the string form is exactly what the weakest-rung argument is about: a digest whose algorithm is unstated is a claim whose strength the reader can't evaluate.
> >
> > One correction to Emek's own finding, and it makes it worse rather than better. He writes that `subject` is an object with `kind` and `ref`, and that neither word occurs in the Internet-Draft. `ref` occurs zero times, which is right. `kind` occurs three times, and every one of them is `basis.kind` or the ordinary English word. So the schema requires `subject.kind`, and a reader who does meet the word meets it bound to a different object meaning something else. That's worse than absence, because absence at least reads as absence.
> >
> > Reader B took R0's "MUST name a subject" at face value, expected a string, and refused all fifteen under shape, which is why its attribution is 0/10. Emek's line for it is the one I'd keep: a class where every document fails the shape check tells its author nothing about the rules underneath. And `withheld_digest` cost reader A its only lost verdict on PV-04, because it looked for `digest` and for `hash`, the two names the prose suggests, and found neither. One member name, and a conforming document reads as non-conforming.
> >
> > NC-05, in my own negative control, without either of you arranging it. Reader A refuses NC-05 under R1 and R5 together. That's the analytic point arriving empirically inside the vector I wrote: a document violating R5's second sentence has already violated R1, so the mutant survives R5's removal. Emek reached it by reading and Walter reproduced it from the other side. My own control shows it, which is better evidence than either reading of it was.
> >
> > Walter found what sits underneath: whether 7.2's "the class MUST fail" incorporates 7.1's refused-by-the-rule-it-targets requirement. Attribution-aware, his R5 mutant dies. Mere-refusal, it survives, which is the survival Emek measured. Same protocol, two readings, opposite kill counts, and it's the load-bearing sentence of the whole conformance section.
> >
> > Emek, on the part of your message that wasn't about my draft. You could have pointed only outward and you didn't. An implementer reached 13/13 against your published vectors only after opening your source, and four things were nowhere in your documents: what the Ed25519 signature actually covers, that the sequence counter advances by exactly one, which absent fields are schema errors rather than tampering, and the order the checks run in. The last one is the one worth the thread: run the signature check first and a deleted receipt reports as a bad signature. True verdict, wrong reason. Check order is a wire fact and almost nobody writes it down. That's the same failure as `kind` and `ref`, and you found yours the same week you found mine.
> >
> > So the claims become, and all of it goes into `-01` with mechanism rather than as quieter sentences:
> >
> > Nine rules of which eight are exercised, R0 tested by nothing. Walter has that one concretely: silencing R1 through R8 kills the class eight times, silencing R0 leaves it passing, because no vector exercises shape alone, so a verifier with no shape checking whatsoever agrees on all fifteen. One R0-only negative control closes it, and until it exists the schema is normative and untested in the same breath.
> >
> > Agreement among implementations on the rules and not on the normative shape. That sentence is now measured rather than hedged.
> >
> > And the production-fixture claim comes out. Walter: Section 7.4's fixtures contain no `cap/1` document at all, both are `certisyn.verdict-document/1.0.0` hosts carrying the older coverage shape, and grep for `cap/1` returns nothing in either. So "correctly refused under R1" has no referent in the artefacts it cites. Your line for it is right: the claims most likely to be false are the ones nothing was pointed at, and these were never pointed at a CAP-1 verifier.
> >
> > The denominator has two doors, not one.
> >
> > Walter moves the edge after the answers are known: 500 checks, forty ugly, declare 460 on the `declared` basis, eight for eight, `complete: true`, perfectly accounted, about a population drawn after the fact. His sentence goes in the draft: the information didn't survive being moved from the remainder to the denominator, it just moved.
> >
> > Emek then leaves the edge alone and moves the claim instead. A stratum states which classes of claim it supports and nothing requires the cited claim to fall inside what it states. Five TLS configuration checks declaring `supports: ["absence-of-any-vulnerability"]` and bounding "no vulnerability was observed in the release" is conforming under both his verifiers. R8 checks presence. The failure it names is containment.
> >
> > The R7 incentive is the third face. A check you expect to error is safer never dispatched, because running it and erroring costs `complete` while declining to run it keeps `complete` with a tidy disposition. It rewards not looking, and nobody has to write a false statement to use it.
> >
> > The closed vocabulary isn't closed, and you found the boundary from four directions. `not_sampled` and `not_yet_due` from Walter, and his R4 argument settles the first: if an enumeration must state its method because the method determines what the enumeration could not see, then sampling is such a method and the undrawn units are none of the eight. `access_denied`, because landing an active refusal beside a missing licence loses the most interesting event in the run. `aborted_before_dispatch` from Tiago, with the sharper half being that `integrity.complete` speaks only of dispatched units, so a clean operator cancellation keeps `complete: true` while part of the eligible population was never reached. And Emek's unit that was dispatched, ran, terminated normally and determined nothing, which `failed` misdescribes and `unavailable` misdescribes and `examined` counts anyway.
> >
> > Emek, you declared an interest before anyone could notice it. That case is right on its merits and I'd have reached it more slowly without you naming it. `superseded` I want and am not adding yet, because the successor pointer is a different shape from the other dispositions and I'd rather get it right than get it quickly.
> >
> > The basis trichotomy, and two repairs that aren't alternatives. Walter and Tiago reached the derived population independently, and Tiago's note is the one I'd keep: a composable or `derived` basis preserves how the population was obtained, Walter's enumeration digest fixes which population was obtained, and neither substitutes for the other because a digest of a set doesn't let anyone re-derive it without the source and the predicate. Both go in. Walter's re-derivability axis then replaces the trichotomy: external artefact, internal artefact, or none. That partition doesn't leak, and `declared` comes to mean exactly one thing. The argument that convinced me is that the careful ones currently get punished, and a vocabulary that penalises rigour gets routed around by the people you most want using it.
> >
> > `withheld` is incoherent, and the vectors already disagree with the text. Tiago has it analytically: Terminology says a disposition is why a unit was not examined, Section 6 says `withheld` is examined, Section 4.1 puts it in `unexamined`, and R1 counts. No count assignment preserves all four. Plus R2 requires every unexamined entry to name a unit while the privacy rationale exists so a sensitive unit needn't be named. Walter settled it empirically in both halves: PV-04 carries eligible 7, examined 4, unexamined 3 with the withheld unit among the three, so the class counts `withheld` as unexamined against Section 6, and the withheld entry names its unit, `selector.ts`, against the privacy rationale. The vectors have been practising the repair on one axis and refusing it on the other. Tiago's two-axis split, examined and disclosed, is the fix.
> >
> > The pinned bundle. Built, not promised.
> >
> > class digest 742509bba744a1b6bf57a057a7769db00d583dbf656648218583a53dcac51254
> > bundle digest 7e3e54963de75316e41a957447b290739bfac5c408f9d973a66f04cf7313dca7
> > MANIFEST.json 0637ea1db3d330aa616e20c1727a191f1065b250e8f2f2df59db2345fe32ce59
> > archive 680e7d20862fee173c568cdf2f384e5bfa0d4fb07df614fc48b22f438fd241ad
> > members 42, of which 15 are the conformance class
> > source Certisyn-Inc/certisyn-drafts @ 0980d3201aa2caab3cbad5c6e9bc99b422370b43
> >
> > Walter, both digests you pinned reproduce exactly against that tree, `170aa81e...` for the vector manifest and `4453f216...` for the schema.
> >
> > Emek, one question about your reproduction, and I think it's a real hazard rather than a nitpick. You wrote that Walter's digests reproduce "exactly once line endings are normalised." The bundle pins SHA-256 over stored bytes with no normalisation, deliberately, so if your checkout is translating line endings then the bundle digest will not reproduce for you as specified, and the artefact built to end this class of ambiguity has one in it. Can you tell me whether that was a checkout setting on your side or a genuine difference in the stored bytes? If it's the second, the bundle is wrong and I'd rather know now.
> >
> > Your class digest doesn't reproduce, and that turned out to be the most useful thing in the exercise. "SHA-256 over the sorted per-file sha256 list of the fifteen" fixes the information and not the representation. I tried forty-four readings of that sentence against your value and none reproduced it: sorted by path or by digest, joined by newline or nothing or comma or space, with and without a trailing byte, hex or raw octets, with and without the filename, in `sha256sum` order or reversed, over fifteen files or sixteen, over stored bytes or canonicalised JSON.
> >
> > That isn't a criticism of the proposal. It's the proposal's own argument arriving one level up, and it's why the bundle specifies the construction to the octet instead of describing it. Six points, each naming a byte: enumerated member set never inferred from a directory listing; SHA-256 over stored bytes with no normalisation; ordered bytewise over the UTF-8 path; one line per member as lowercase hex, one U+0020, POSIX relative path; joined with U+000A including after the last; SHA-256 over that sequence.
> >
> > One departure from your construction, with the mutant that earns it. The digest is over path-and-digest lines rather than over digests alone, because a list of content digests commits to the multiset of contents and not to which file holds which. The bundle's mutation test swaps the contents of NC-01 and NC-02 and prints the path-blind digest either side:
> >
> > path-blind class digest, before: 47314682fddd39da
> > path-blind class digest, after : 47314682fddd39da
> > UNCHANGED, so a digest over content alone cannot see this
> >
> > The bundle carries its own verifier and its own mutants. `verify_bundle.py`, 42 members, 0 failures, and it reports every failure rather than stopping at the first, which is Emek's short-circuiting finding applied to the tool. That finding deserves its own line, because it generalises past both our drafts: refused by the rule it targets is only checkable against a verifier that reports every refusal. Against a short-circuiting one it's a fact about check order.
> >
> > `mutate_bundle.py`, four mutants, four killed, and the crediting rule there is a set rather than a singleton, for your reason rather than mine. Altering a vector must move its member digest, the class digest and the bundle digest together, so a mutant cannot produce exactly one failure. That is NC-05 again, in a different tool, within an hour of reading your report on it: a protocol demanding exactly one broken rule per control cannot be met where the rules entail one another. I hit it building the thing that exists because you found it.
> >
> > Standard library, no network, no arguments. Tiago, that should meet your bar; if it doesn't, say where and I'll fix the bundle rather than argue.
> >
> > Tiago's freeze discipline, agreed and extended: you, Walter and Emek's two readers each hash implementation and interpretation notes before seeing another's, then run against this. Agreement is then worth something and disagreement is worth more.
> >
> > Iman, thank you for the priority note, and it wasn't necessary from my side. An additional implementation is exactly as useful as a fourth one, and PR #630 written from `-00` is another reading of the same text by someone I haven't spoken to. Yes to the schema-shape and examined-set negative controls against the pinned commit, and they can now cite a class digest rather than a commit.
> >
> > One thing your break has already changed elsewhere. I read Walter's first message, went looking for the same shape one level up in the other draft, and it was there. ARP's evaluation sweeps carry an accounting identity over a bracket of ledger sequence numbers and check that nothing was skipped inside the bracket. Nothing required the bracket to abut the previous one, so a sweep could be complete over an interval beginning after the entries an operator would rather not have examined, and every rule passed. Now fixed: brackets must abut, and any range deliberately not examined is individually disposed with a registered reason, where the registry refuses a reason the reader can't check for itself. Walter's sentence is quoted there with his name on it.
> >
> > Different subject matter, same defect, found by reading a review of a different document. Which is the strongest argument any of us has made for the shared substrate, and it wasn't made in the abstract.
> >
> > Keep going. This is the most useful day either draft will ever get.
> >
> > Joel
>
> --
> SCITT mailing list -- scitt@ietf.org
> To unsubscribe send an email to scitt-leave@ietf.org