[SCITT] Re: Closing omission from the receiver's vantage — what a record must carry

Pablo Play <playplay2736@gmail.com> Fri, 21 August 2026 17:44 UTC

Return-Path: <playplay2736@gmail.com>
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 BF2DF12D74F75 for <scitt@mail2.ietf.org>; Fri, 21 Aug 2026 10:44:07 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ietf.org; s=ietf1; t=1787334247; bh=yqFY/F2sRpD2RmMke1HWeVQ53+y5XI1msXwgCmnp+zI=; h=References:In-Reply-To:From:Date:Subject:To:Cc; b=rwbcqg6/GlBpGGhbIapajwR3sai6OJPCVTPDpg75NNvX3ga8rFb77FLGRzf9Gur1A OJUrU1YmWSh6LrvOTIYGqOY/o2EUBc+SNPo3uElI62ULlZ12K1YhYvYb2wrd01GUur ptFNTsY3k7irZAJpvO4fInhsqrQ5xYXDYRkmJncI=
X-Virus-Scanned: amavisd-new at ietf.org
X-Spam-Flag: NO
X-Spam-Score: -0.848
X-Spam-Level:
X-Spam-Status: No, score=-0.848 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, FREEMAIL_ENVFROM_END_DIGIT=0.25, FREEMAIL_FROM=0.001, GB_AFFORDABLE=1, HTML_MESSAGE=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001] autolearn=no autolearn_force=no
Authentication-Results: mail2.ietf.org (amavisd-new); dkim=pass (2048-bit key) header.d=gmail.com
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 mL-eJSmDBOPs for <scitt@mail2.ietf.org>; Fri, 21 Aug 2026 10:44:04 -0700 (PDT)
Received: from mail-qv1-xf29.google.com (mail-qv1-xf29.google.com [IPv6:2607:f8b0:4864:20::f29]) (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 82C3412D74F2E for <scitt@ietf.org>; Fri, 21 Aug 2026 10:44:04 -0700 (PDT)
Received: by mail-qv1-xf29.google.com with SMTP id 6a1803df08f44-90c776f6c13so12297116d6.1 for <scitt@ietf.org>; Fri, 21 Aug 2026 10:44:04 -0700 (PDT)
ARC-Seal: i=1; a=rsa-sha256; t=1787334244; cv=none; d=google.com; s=arc-20260327; b=aajq3BHAhhY75rtNsrZUvEpXc0oa2hfZNjFJP5voub3En2QeBVx7ZKAVox5tQOSTPC AnEYJ6jG2lrozUr7x5vV/r/4w+J/v8gmPIBddYe5OG49bNpuYtk/m2TkenDTvhdZmXVL /wqKOk7SWgrbpBR+YJRcw3nqF4mbKEDXY3EdTzVoHTv35qIYhw6skf/O3io6ai7EHDdn 2hcAcITzLnH7ynI3FiBCWRQeoeg52WGE5ZiFZGPDpG0U48PtJA51JMe9So5gnDHBth/m HxakvTasDvuw7heS1IvpFFiejxkzoG+vmJsVZPU4rJJIzRwCeVwMdEgGni771EVlG+9y KpCw==
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20260327; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:dkim-signature; bh=6giPdwcbgXWA0XQqQ+blPT0FnYlMAw8IzEffOu8jGS0=; fh=IvdOInwrF3QvXGFvlD62u+E70Pyg5LPQFU6899UKkYg=; b=MTLN8HEMjVAJliKCi8+I1eQUswzR01iCM/xEL8apD0Uru1FfmqGWmpAmm8z9YgpIAZ hkTNhJWxjoVw8idRWmklVR2Wm/FgYARtiPUNvL+CZKu2nHS9/7gphTy/2Ocl0x/49YMq c8kxYLGtvyRAtUKbCh8d5Sh5pGeVkhdSf+aelqNuE1k1+p90ngY5woGBh/aQKbKb0vVL ZNzo1wFE/0MSXTOWsdi0zIlaR5F+8woefvA+i9EgFReSPtMQfOv/P0bqjIvZfbHGrbwI KZFq6xAh1iAyATC9PdcxoLb0qoiXDa6jhwZlVT2eut9vJdZkdbnfKE/J2rqC6AO7+7r8 +I5g==; darn=ietf.org
ARC-Authentication-Results: i=1; mx.google.com; arc=none
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1787334244; x=1787939044; darn=ietf.org; h=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=6giPdwcbgXWA0XQqQ+blPT0FnYlMAw8IzEffOu8jGS0=; b=SmwcNq4ea6JBfNYBm+KVeMUoB3p3MsfP50waMqI3aEGGK/sYxB+ZISwO+nA7dqWkZQ ag2+9rF+f1zWvEJHaIzJDgLU5pRWnOzbPvWGNCJKhx76YIe3rnTZd1VWcQ4tDTGBDE5k Vxul+kJ+w6W3AXmSERjCRo+K6zwaduWapT5Dl4N0LUb5Ih07vhx9CYGlLUcXmwZtHDdq 6hpeWo1y+JNdBRWPfM914KSwXQAVM955/0bmEmrVWvBNdXomVT2M1HUcpymFe2DiCp9W liq0H90TpPjOwTQd+yAq1ePTgqPgfTPZjuiybjDxi2ZckhsioDoLCBrUnvcCwVxndA47 7xDg==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1787334244; x=1787939044; h=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=6giPdwcbgXWA0XQqQ+blPT0FnYlMAw8IzEffOu8jGS0=; b=pntSRdbrDwOz8tkqmkyMOJHnZi9op8+B8uw3E16auSFq1OHTHMr4aJ5auWaVrFw/6C g196Y6pCM5hKcs0lQNkc5824LKVqtS0MoZrftlHTsyybd5104IYZnRMhBBtoZtM6ReSl 4HrkFhasUANvN+7qBJRGJ7Jd2ESpHkpLR+Sx3HOZPioGlKusJvO+8XEjnRKiaVwQq2rh nvSoT9vMy5CZZCUN3ka1RbadcU48Eym/qtGntr+nKTisU3+7NDEaqWgGSJbbfxfEFjBW 7HjH00BC8mCLvnqt6hgGaG9orMVIbq0aeovpaR/QGLoShpSYlVicpv5Cwj2ZksXcdlLx CXqw==
X-Forwarded-Encrypted: i=1; AHgh+RoIkjw9UQM1+DvX8wxqtADIhO/g+ntQMhjamWojJJKrQLlks0qqaxhXjqC9+KRHnjh+3HW+XQ==@ietf.org
X-Gm-Message-State: AFuF++l4vL3J59gFUk0dDGBJdSEMwvJ0GXv02QVtL8D1fjH8Y4EOLVxJ yoXcFZQN1W7F7vM62Qa83dNa7Rg76n7lFOxQlXqyVBMy8EDHVjvhvmIcT8utwy0jr9fF8Zw64/P eL+T57hFyOqfBuAU7w5Q/IrZ4sths8uY=
X-Gm-Gg: AR+sD101eVw/TR8AbmPYkbmHfcoJqp43+mpzOUGuROpQRHla1xsZnw0OWpRsKSc2gJy p9wqHSYuoU9/RmQKswZpxVi497WeTbTP2Dyqtc8gaRD8MlbeoF3t+2Y5rjCo4JQfO8GRjHncX9e eNDuVokHn9mzUGH8UMbFiMRAq/EH8IShyj3FHkBUb6o5GwxRspcTI7TDTQUBTAE6fdZy0Y1HEg7 rVCTzg+tb8OyWbmda+rr5DPFq7p4qvGR3LLHowwwtfjgFUCcZZV9q7NtKXsDayx3Ku7dtLzr6+3 nWYuM3Edlzn9U2XrhxD9W6L7uoR+nlqqyItQsxfdA74BurF0VekUNwyFn5qtdTi7JTsgKjarntd EXAK7HYVNI+xlkDm12DzJEOp6nzQ+PExu4cQuHs7VN0qrvwmW33fXU1q4rIfGaphmAu0SjbA745 FNnLg+n+5KllSg3soOef2/tfzjrGXs578B4BeP6+g4AvxbfqTdBibPjBPbWn2qBXGOyoTb8w==
X-Received: by 2002:a05:6214:1bc9:b0:8ea:efae:ab26 with SMTP id 6a1803df08f44-90c8079a9dcmr77162786d6.0.1787334243496; Fri, 21 Aug 2026 10:44:03 -0700 (PDT)
MIME-Version: 1.0
References: <1787262784652143705.1787262784@conarium.dev> <CALc05oFWK2_mQEB9JLRorCS5QLc0rPrJxj3BMc0r0B82ZcH_mg@mail.gmail.com> <1787272059233193813.1787272059@conarium.dev> <CALc05oGzHYVzZjWYDFCa0FYzSTHAz4_xY0wMr80j-UbPE5-UoA@mail.gmail.com> <z7XRDPPaX3By1sxJwdNM8-FqQMDTOW43O10genKixWn3mEz5m_xkYFwdQ324tf5_ATaSPdhnIgKg-uSwdLGy9twqj8odSf1ZqeUtNpFzzKk=@vaara.io> <CANWAHpowbgTkTmMQ-sDs1pgZF-UAgfLxZN+DqfWLxLyMPY_E-w@mail.gmail.com> <1787312175766668752.1787312175@conarium.dev> <CANWAHpqWvW3etxM7NJ3ef43mTaqQLGCi+EO8uKfZopejRJBLoA@mail.gmail.com> <1787328731104225837.1787328731@conarium.dev>
In-Reply-To: <1787328731104225837.1787328731@conarium.dev>
From: Pablo Play <playplay2736@gmail.com>
Date: Fri, 21 Aug 2026 14:43:51 -0300
X-Gm-Features: AcwNN1VkfamgO1DXh7m7zAOYPL9lDkuRY-R51IgGQ9Qj8tyDUv2rgauonvX1A5o
Message-ID: <CANWAHprGQuJ_GmAyfm1cbDe5e8jkSDUcGeJYsX6QZp0+Bao2Fw@mail.gmail.com>
To: e.dogru@conarium.dev
Content-Type: multipart/alternative; boundary="000000000000adb6550659922e22"
Message-ID-Hash: 4NNJXD6NDUPM2HFGQ7PI3JFWBM2HZAMP
X-Message-ID-Hash: 4NNJXD6NDUPM2HFGQ7PI3JFWBM2HZAMP
X-MailFrom: playplay2736@gmail.com
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: hello@vaara.io, wdhawkins46@gmail.com, scitt@ietf.org, jhillier@certisyn.com, nenadvasic@protonmail.com, Todd.Gibson@t-mobile.com
X-Mailman-Version: 3.3.9rc6
Precedence: list
Subject: [SCITT] Re: Closing omission from the receiver's vantage — what a record must carry
List-Id: "Supply Chain Integrity, Transparency, and Trust" <scitt.ietf.org>
Archived-At: <https://mailarchive.ietf.org/arch/msg/scitt/qbu2LPIdZI4ALBPQy61xo-EZ_1o>
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>

Emek,

  Appreciate the shape, and the correction you caught before sending it.

  On the defect: we don't have a live case of it yet, because we haven't
built the rejection
  path at all — packet_version exists in the spec as a forward-compat
field, but no verifier
  code enforces it today. So there's no wrong answer in production, just no
answer.

  Your last paragraph is the useful one for us. Our read path (trail
lookup) is binary by
  construction — SQLite, no partial reads — so we may get the
defined-and-empty vs.
  not-yet-defined discrimination for free at write time rather than
reconstructing it from
  the digest the way you had to. Haven't verified that holds once we
actually put version
  inside the preimage instead of the current domain-tag prefix. Taking it
to design before I
  claim it works.

  No date on this yet. Will report back if the binary-read shortcut holds
or if it turns out
  to be wishful thinking.

  Pablo

El vie, 21 ago 2026 a la(s) 1:12 p.m., <e.dogru@conarium.dev> escribió:

> Pablo,
>
> Thank you for saying it plainly. Here is the shape rather than the
> principle,
> since the principle was never the hard part.
>
> What makes the null branch free for us is not the null. It is that the
> version
> identifier is inside the preimage, so a digest carries which schema was in
> force
> when it was taken. Concretely: our content hash is computed over the
> record with
> hash, sig and anchor removed and everything else left in place, and the
> version
> string is one of the fields left in. Delete it from a published vector and
> the
> recomputed hash moves. That is the whole mechanism.
>
> The cost, so you can price it before adopting anything: the version becomes
> load-bearing. It is no longer a label a producer may write loosely,
> because two
> records that differ only in it are two different digests, and a producer
> who bumps
> it by accident has forked the corpus. We accept that because the
> alternative is a
> member whose absence a reader cannot attribute.
>
> The part I would not copy from us, and I had this wrong until I went and
> ran it
> before sending. I was going to tell you the version was bound to the
> schema only
> by convention. It is not: a version string the verifier does not know is
> rejected,
> exit 20. The real defect is what that exit code says. A record from a
> version
> newer than the verifier reads as *not a receipt at all*, rather than as a
> receipt
> from a version this reader cannot evaluate. Those are different facts
> about the
> world and the tool reports the wrong one, which is the same shape as the
> anchor
> case I described in the other thread. I have no fix for it yet. If you
> build the
> version into your preimage, give yourself a third answer for that case
> before you
> need it.
>
> If your read path is binary by construction, you may get a cheaper version
> of this
> than we did — the discrimination you need is between defined-and-empty and
> not-yet-defined, and a boolean read path already knows which of those it
> is at the
> point the record is written. We had to reconstruct it from the digest.
>
> Emek
>
>
> On Fri, Aug 21, 2026 at 2:55 PM Pablo Play <playplay2736@gmail.com> wrote:
>
> Emek —
>
>   Confirmed, that's the right read of it — no correction needed to how you
> framed the
>   partition.
>
>   On your fourth point: we don't have it. No version string in the
> preimage — absent
>   optionals are null-or-key-omitted depending on the caller, and nothing
> in the digest says
>   which schema was in force when it was taken. So the flag-day Joel
> described in the encoding
>   thread is one we'd actually pay if we introduced a null-for-absent rule
> today. We don't
>   have the piece that makes it free for you. Worth being explicit about
> rather than finding
>   out later.
>
>   Pablo
>
> El vie, 21 ago 2026 a la(s) 8:36 a.m., <e.dogru@conarium.dev> escribió:
>
>> All,
>>
>> Pablo — the partition you merged is the third independent one, and the
>> three
>> disagree about enough that the agreement is worth naming. Walter reached
>> it from
>> the ladder, Henri from a closed reason set in a release condition, yours
>> from a
>> binary read path where `trail_not_found` is unreached and the rest ran and
>> failed. None of us started from the same problem, and none of the three
>> collapses
>> a cleanly-resolving value into whichever adjacent state was easiest to
>> code
>> against.
>>
>> I have the fourth, and I am posting the cost rather than the agreement,
>> because
>> the cost is the part that is not obvious.
>>
>> The receipt format takes the null branch: an absent optional is **present
>> and
>> null**, never omitted, and a receipt that omits the keys is rejected as
>> malformed rather than read as empty. Vector `013-disclosure-keys-omitted`
>> exits
>> 20 for exactly that.
>>
>> Joel's objection in the encoding thread is the right one to raise against
>> it: a
>> null-for-absent rule makes every digest computed before a member existed
>> incomparable the day it is introduced. That is a real flag day and we pay
>> it —
>> except we do not, and the reason is worth stating, because it is not the
>> null
>> rule that saves us.
>>
>> The version string is inside the preimage. Removing `v` from a published
>> vector
>> changes its content hash, so the digest carries which schema was in force
>> when it
>> was taken, and a member absent under 0.3 is attributable rather than
>> ambiguous.
>> `012-mixed-chain` is a 0.3 receipt followed by a 0.4 receipt, and the
>> chain
>> verifies. Both were published before this argument started, so I am
>> reporting a
>> property rather than claiming foresight.
>>
>> Which lands where Joel's own thread lands: *if you omit, carry something
>> in the
>> preimage that says which members were defined when the digest was taken.*
>> We do
>> not omit, and we carry it anyway. The version is doing the work the
>> omission rule
>> was invented to do, and the null is buying the distinction between
>> *declared
>> empty* and *never written*. They are separable, and I had them mixed up
>> until
>> this thread.
>>
>> Everything above is in `@conarium-ai/core@0.2.39` on npm, vectors
>> included.
>>
>> Emek
>>
>>
>> On Fri, Aug 21, 2026 at 12:32 PM Pablo Play <playplay2736@gmail.com>
>> wrote:
>>
>> Henri, all —
>>
>>   Second empirical data point under the closed-enum property, from a
>> different mechanism than
>>   Vaara's release condition but the same shape: a binary result whose
>> reasons already
>>   partition into two non-overlapping categories, documented additively
>> rather than widening
>>   the enum.
>>
>>   verify_chain() in our stack returns valid: false for two structurally
>> different situations
>>   — a trail that was never reachable to evaluate, and one that was read
>> completely and failed
>>   a real check. The read path is binary by construction (single-row
>> lookup, no partial
>>   reads), so trail_not_found always runs first against the raw result,
>> and everything
>>   evaluated after it — including missing_signature_ref — is a check
>> against a record we
>>   already read in full. That gives a clean partition without touching the
>> valid contract:
>>
>>     trail_not_found                  -> unreached
>>     missing_signature_ref            -> ran-and-failed
>>     delegation_ref_parent_mismatch   -> ran-and-failed
>>     cycle_detected                   -> ran-and-failed
>>
>>   Merged as-is, 69 lines added, 0 removed (commit e12658d,
>>   github.com/giskard09/argentum-core, negotiation-ref.md).
>>
>>   Same underlying rule as your blocked-but-verified receipt: a value that
>> resolves cleanly
>>   deserves its own place in the partition, not a collapse into whichever
>> adjacent state is
>>   easiest to code against.
>>
>>   — Pablo
>>
>> El vie, 21 ago 2026 a la(s) 2:28 a.m., Henri Sirkkavaara (hello@vaara.io)
>> escribió:
>>
>>> Nenad, Walter, Joel, Pablo, Emek, Todd,
>>>
>>> The principal row is right and I would take it further than a row. Your
>>> revocation case and the receiver's settlement case are the same shape at
>>> two different levels, and neither party can be substituted for the other,
>>> which by this thread's own argument puts the vantage question in the
>>> substrate rather than in any one draft.
>>>
>>> On the closed-enum property, I have something to put under it rather
>>> than another agreement.
>>>
>>> Vaara 1.71.0 ships a release condition: money is held against a signed
>>> statement of what must be proved, and a receipt proving the authorised
>>> action happened is what releases it. Evaluation returns one of four states,
>>> each carrying a reason from a closed set. The mapping from reason to state
>>> is a table, not control flow, so no code path can file a forgery under a
>>> hold.
>>>
>>> The partition runs on one axis. A broken signature, a receipt under a
>>> key the condition does not pin, or evidence that does not resolve to the
>>> digest the receipt signed are failures as evidence, and they refuse. A
>>> missing receipt, a receipt for another action, another authorization, or
>>> one that soundly proves a refusal are sound and insufficient, and they
>>> hold. Soundness is checked before the clock, so an expired window cannot
>>> swallow a tampering finding.
>>>
>>> Eight vectors in tests/vectors/release_condition_v0, all four states
>>> present, and a checker that imports no Vaara and recomputes every verdict
>>> from the case bytes. Among them is a receipt that verifies correctly and
>>> proves the action was blocked. It must not release, and treating it as a
>>> plain false would put it in the same state as a forgery.
>>>
>>> DOI 10.5281/zenodo.22029444 if it is useful to cite the exact bytes.
>>>
>>> *Henri Sirkkavaara*
>>> *Vaara *- Runtime execution layer for AI agents
>>> *Built to see over the noise.*
>>> vaara.io
>>> Helsinki, Finland
>>>
>>> On Friday, August 21st, 2026 at 04:10, Walter Hawkins <
>>> wdhawkins46@gmail.com> wrote:
>>>
>>> Emek,
>>>
>>> You came back with the check and what it caught, so here is mine — same
>>> shape, a day behind you.
>>>
>>> The rule, as shipped. An anchored sequence moves a verifier's floor only
>>> when all of the following hold: the calldata parses and names this grant;
>>> the key segment equals the grant's accountant; the anchored content was
>>> actually retrieved; the anchor digest recomputes over the retrieved head;
>>> the head's signature verifies; and the head itself names this grant, this
>>> accountant, and this sequence. Anything short of that is ignored with a
>>> warning naming the reason, and a refusal can only lower the floor toward
>>> the tamper-evidence downgrade, never raise it. The old scan — the one that
>>> trusts the sequence printed in calldata — survives under an UNVERIFIED
>>> label for survey work, because a claimed sequence is still a lead worth
>>> following. It is no longer anything a verifier may refuse an honest head
>>> against.
>>>
>>> Shown failing before wired in, on your reasoning that a check which has
>>> only ever been green demonstrates nothing. Four controls:
>>>
>>> - The forged-key attack from my last message, run for real: a stranger's
>>> anchor claiming sequence 999999999 under the accountant's public key. The
>>> unverified scan reads 999999999 — poisoned exactly as I described it two
>>> days ago. The verified scan holds the floor at the genuine head and prints
>>> a warning naming the anchor it ignored.
>>>
>>> - An anchor whose retrieved head does not reproduce the anchored digest:
>>> no floor movement.
>>>
>>> - Calldata claiming one sequence over a head that states another: no
>>> floor movement.
>>>
>>> - No qualifying anchor at all: the floor is null, and null is not zero.
>>> "I could not derive a floor" is the labelled tamper-evidence downgrade, not
>>> a fact about sequence 0.
>>>
>>> What it caught immediately: my own anchor. The only anchor we have ever
>>> written to a chain — the Coston2 transaction at block 34259963 that I
>>> brought to this thread as evidence — is refused by the rule it motivated. I
>>> read its calldata back off the chain today: it parses, and it carries no
>>> key segment at all, because the grammar predates the hardening; the head it
>>> points to predates the accountant field. Two independent grounds, either
>>> one fatal to floor-eligibility. Your check's first catch was your own
>>> sentence; mine refused my own anchor. It stays in the record, labelled, as
>>> tamper evidence of the day the wiring first worked — which is exactly as
>>> much as the hardened rule permits it to be. The lesson I passed on last
>>> time, that we anchored a shape we were still editing, now has an
>>> enforcement mechanism instead of a caveat.
>>>
>>> Your 14-versus-15 split is in here too, arrived at separately. An anchor
>>> whose content cannot be fetched is ignored with "content not retrieved, so
>>> its sequence is unverified" — could-not-check never gets swallowed into
>>> failed, and never silently reads as verified. The null-rather-than-zero
>>> floor is the same rule one level up. I'd add both of ours to the pile Joel
>>> is counting: the weakest-rung rule keeps being reinvented at whatever layer
>>> someone is standing on, which is the strongest argument yet that it belongs
>>> in the substrate stated once.
>>>
>>> Two limits, stated now rather than found later.
>>>
>>> First, the verifier takes the retrieved heads as inputs; where they came
>>> from is outside the rule. Joel's placement rule — state where the evidence
>>> is obtained, not only where it is produced — lands on this with full force.
>>> A verifier handed heads by the executor it is auditing has re-derived at
>>> the second placement, and the result object should say so. Mine does not
>>> yet distinguish the placements; that is the next honest gap.
>>>
>>> Second, floor-eligibility depends on retrievability, so the floor's
>>> strength decays with content availability. An adversary who cannot forge a
>>> floor can still lower one by making anchored content unfetchable. That
>>> fails in the right direction — a downgrade rather than honest heads refused
>>> — but it is a downgrade an attacker can induce, and the record has to name
>>> it, or "no floor" reads as "nothing was ever anchored", which is a
>>> different claim.
>>>
>>> Walter
>>>
>>> On Thu, Aug 20, 2026 07:27 PM, e.dogru@conarium.dev wrote:
>>>
>>>> All,
>>>>
>>>> I said I would come back with the check and what it caught rather than
>>>> with a plan. It is written and merged; this is what it caught. Walter's
>>>> rung 3 question gets a measured answer at the end, because it turned out I
>>>> could check it rather than argue it.
>>>>
>>>> The problem is in -05 in my own words: four sentences in the
>>>> Implementation Status section of -04 were accurate the day they were
>>>> written and false within days, every one of them claiming less than the
>>>> code did, and nothing in the repository compared that section to the tool.
>>>> They were found by a reader holding the document beside the output.
>>>>
>>>> The check runs the section instead of reading it. Three declarations of
>>>> one fact exist: the code, the prose, and now a claim table between them,
>>>> because prose cannot be executed. Each behavioural sentence is bound to a
>>>> run of the shipped CLI over a named fixture, and two directions are
>>>> enforced. Every value a run produced must still appear in the sentence that
>>>> states it, and the number of sentences must equal the number of claims. A
>>>> sentence with no claim is one nothing measures. A claim with no sentence is
>>>> a measurement the document dropped.
>>>>
>>>> The revision it reads is derived from what is in the repository rather
>>>> than named in the check, because a hard-coded revision is the same class of
>>>> stale declaration the check exists to catch.
>>>>
>>>> I showed it failing three ways before wiring it in, since a check that
>>>> has only ever been green demonstrates nothing:
>>>>
>>>> a value edited out of a sentence
>>>> -> the sentence no longer contains observed-without-receipt
>>>> one bullet removed
>>>> -> states 4 observed behaviour(s), the claim table runs 5
>>>> a fixture changed so the tool's outcome moved, sentence untouched
>>>> -> item outcomes are ["excluded","indeterminate"],
>>>> the table says ["excluded","observed-without-receipt"]
>>>>
>>>> The third is the one that matters: the code moved and the sentence
>>>> stood still, which is what happened four times in -04.
>>>>
>>>> What it caught immediately is a sentence of mine. -05 says "The
>>>> implementation's test suite contains no check that compares this section
>>>> against what the code does." From the merge commit that is false, and a
>>>> posted draft cannot be edited, so it is the first correction -06 owes.
>>>>
>>>> Two limits, stated now rather than discovered later. It pins the
>>>> behaviour table and not the prose around it, so a paragraph can still go
>>>> stale in a way nothing runs. And a red has two honest fixes: change the
>>>> code back, or write the revision that says what the code now does. Editing
>>>> a posted draft is not one of them, which makes the cost of drift a document
>>>> rather than a diff.
>>>>
>>>> Walter, on rung 3. You put it as: an external anchor is not
>>>> automatically rung 3, an anchor is a claim by whoever paid for it, and a
>>>> profile that says "anchored" without saying "and re-derived" has described
>>>> rung 2 with extra steps. I went and looked rather than answering from
>>>> memory, and the implementation agrees with you, which I did not know for
>>>> certain before you wrote it.
>>>>
>>>> --anchor-check deserialises the timestamp proof, refuses a proof whose
>>>> digest is not the chain head, walks the attestations, and where the
>>>> attestation is Bitcoin it fetches that block and compares the digest
>>>> against the merkle root. So the re-derivation is in the path and not in the
>>>> prose.
>>>>
>>>> The part I would not have thought to defend, and which your framing is
>>>> the reason to mention: it separates two answers that a single exit code
>>>> would have merged. A proof that fails to verify exits 14. A proof that
>>>> could not be checked at all, where the block could not be fetched, exits
>>>> 15, and 15 is evaluated first, so "I could not check" never gets swallowed
>>>> by "it failed". Returning 0 there would have been the same error in the
>>>> other direction: the caller has to know the anchor was not verified, not
>>>> merely that it was not disproved. That is the weakest-rung rule applied to
>>>> our own tool, and it was written before anyone asked us for it, which is
>>>> the only reason I can say it now without it sounding convenient.
>>>>
>>>> Emek
>>>>
>>>>
>>>> On Fri, Aug 21, 2026 at 2:50 AM Walter Hawkins <wdhawkins46@gmail.com>
>>>> wrote:
>>>>
>>>> Henri, Joel, Emek, Pablo, Nenad, Todd,
>>>>
>>>> Two corrections of my own before the part I owe this thread, since that
>>>> appears
>>>> to be the going rate here and it's a good rate.
>>>>
>>>> **One.** I used the words "omission-proof" in my own notes and it was a
>>>> rung
>>>> short. Our spend log is chained and gap-free under a signed grant, and
>>>> the head
>>>> that seals it is counter-signed by a named accountant carrying a root
>>>> and a
>>>> running total. That much I had right — it's rung 2. What I had wrong
>>>> was the
>>>> floor. A verifier arriving for the first time, holding no prior state
>>>> and doing
>>>> no anchor lookup, accepts an old validly-signed head together with the
>>>> prefix
>>>> that matches it. Monotonic sequence, perfect arithmetic, short set.
>>>> Henri's
>>>> correction this morning is the same shape as mine, and I'd made mine a
>>>> day
>>>> earlier without noticing what it cost.
>>>>
>>>> Fixed the way Emek's rule says it should be: the freshness floor is now
>>>> a
>>>> required argument, and passing nothing is an explicit downgrade whose
>>>> verdict
>>>> is labelled tamper-evidence rather than completeness. The weakest-rung
>>>> rule
>>>> applied to an argument I had made optional.
>>>>
>>>> **Two, and this is the one I think is worth the thread's time, because
>>>> it's a
>>>> hole in rung 3 itself.**
>>>>
>>>> We put our heads on-chain: a zero-value transaction whose calldata
>>>> carries the
>>>> head digest, the grant it covers, the sequence, and the key that signed
>>>> it. A
>>>> first-contact verifier scans for those and takes the highest sequence
>>>> as its
>>>> floor. That is the external anchor the ladder asks for, and two days
>>>> ago I'd
>>>> have told you it put us at rung 3.
>>>>
>>>> Anchoring is permissionless. That property is why it resists censorship
>>>> and it
>>>> is also the attack. Anyone can write that calldata. The key field is
>>>> plaintext,
>>>> and the accountant's key is public because it's named in the grant. So a
>>>> stranger writes an anchor for my grant at sequence 999999999, my
>>>> scanner reads
>>>> it, and every honest head I produce afterwards is refused as a
>>>> rollback. The
>>>> floor is poisonable by anyone willing to pay for one transaction, and
>>>> the
>>>> failure mode isn't a missed omission — it's an honest record permanently
>>>> refused. We had traded a false negative for a false positive against
>>>> ourselves,
>>>> which is the worse of the two trades.
>>>>
>>>> The fix is that an anchored sequence cannot be read as a fact. It is a
>>>> pointer.
>>>> A verifier deriving a floor has to fetch the anchored bytes, recompute
>>>> the
>>>> digest over them, check the signature, and check that the head it just
>>>> verified
>>>> names this grant and this sequence — and only then let it move the
>>>> floor. An
>>>> anchor whose content can't be retrieved simply isn't floor-eligible,
>>>> which can
>>>> only lower the floor toward the tamper-evidence downgrade, never raise
>>>> it.
>>>>
>>>> Stated honestly about where we are with it: that rule is written into
>>>> our spec
>>>> text and our scanner does not yet do it. What the scanner does today is
>>>> the
>>>> cheap half — it ignores anchors that don't name the grant's accountant,
>>>> which
>>>> closes the stranger-with-no-key case and leaves the forged-key case
>>>> open,
>>>> because that field is unauthenticated. So take the paragraph above as a
>>>> claim
>>>> about what rung 3 requires, not a claim about what I've shipped. The
>>>> re-derivation is the next thing I write, and I'll come back with what
>>>> it caught.
>>>>
>>>> So for the statement I'd put it this way: an external anchor is not
>>>> automatically rung 3. An anchor is a claim by whoever paid for it. Rung
>>>> 3 is
>>>> an anchor plus the verification that recovers what it points at, and a
>>>> profile
>>>> that says "anchored" without saying "and re-derived" has described rung
>>>> 2 with
>>>> extra steps. Nenad, I think this bears directly on precedence —
>>>> ordering a
>>>> revocation strictly against a settlement only means something if both
>>>> anchored
>>>> objects are re-derived first; otherwise you've ordered two assertions.
>>>>
>>>> **What I owe: the rail enumeration.**
>>>>
>>>> Every payment under a grant carries a binding in the one payer-chosen
>>>> slot the
>>>> rail's own signature covers — the EIP-3009 nonce, the Permit2 nonce,
>>>> the XRPL
>>>> InvoiceID. The value is a domain-separated digest over the grant digest
>>>> and the
>>>> payment identifier, so it's derivable by anyone holding those two and
>>>> recomputable from the settled transaction by anyone holding that.
>>>>
>>>> The receiver's use is the part this thread wants. A payee holding a
>>>> settled
>>>> transaction recovers which grant and which payment it commits to from
>>>> the
>>>> artefact itself, without asking the executor which authorisation it
>>>> would like
>>>> to be judged under. And the enumeration runs off the rail rather than
>>>> off a
>>>> list: the payee walks settled transactions to their own address, not a
>>>> set the
>>>> executor hands them. A leg the executor never wrote down is still on
>>>> the rail
>>>> if the money moved, and the party holding it is the party who cannot be
>>>> made to
>>>> un-know it arrived.
>>>>
>>>> Testnet EVM rail, as promised: Coston2. A head anchored as a real
>>>> transaction at
>>>> block 34259963, the calldata read back off the chain and matched
>>>> against the
>>>> signed head, block timestamp doing the ordering.
>>>>
>>>> With a caveat that belongs in this thread more than most. That anchor
>>>> predates
>>>> the hardening I described above — its commitment has no accountant
>>>> field and its
>>>> calldata has no key segment, so it verifies against the code as of the
>>>> commit
>>>> that produced it and not against current HEAD. I keep it as evidence
>>>> that the
>>>> wiring worked on the day, and as a small lesson I'd pass on: we
>>>> anchored a shape
>>>> we were still editing, and permanence is the one property an anchor has
>>>> whether
>>>> or not you were finished. New heads use the hardened shape. I'll bring
>>>> both,
>>>> labelled.
>>>>
>>>> Two limits I'd rather state than have found.
>>>>
>>>> The rail has to enforce slot uniqueness for once-per-payment to come
>>>> free.
>>>> EIP-3009 and Permit2 consume the nonce, so it does. XRPL does not
>>>> enforce
>>>> InvoiceID uniqueness — two Payments carrying the same InvoiceID both
>>>> settle —
>>>> so anyone deriving a cumulative total from XRPL evidence has to
>>>> de-duplicate by
>>>> (grant, payment) and cannot lean on the rail for it.
>>>>
>>>> The second one I had wrong until a review pulled it apart yesterday,
>>>> and it
>>>> generalises past payments. The binding identifies the grant; it does
>>>> not bound
>>>> the amount. The slot commits to the grant and the payment identifier and
>>>> nothing else, so an agent holding the payer key can settle a million
>>>> against a
>>>> payment it reports as one. The cap only binds if the verifier reads
>>>> amount,
>>>> recipient and asset out of the settled transaction and compares them
>>>> back to
>>>> the grant. I had a document claiming one artefact proved both that
>>>> money moved
>>>> and that it moved within authority, and that sentence was doing work the
>>>> mechanism didn't do. Identifying which authorisation governed an act is
>>>> not
>>>> the same as bounding the act performed under it — Nenad, that's your
>>>> item 2
>>>> from the other end, and I think it's a second thing the substrate
>>>> should say
>>>> outright, because the failure is invisible and every incentive points
>>>> at it.
>>>>
>>>> The object model and its vectors are public as of today, as an open PR
>>>> rather
>>>> than anything settled: specs/extensions/authority.md and
>>>> authority-vectors.json in x402-foundation/x402 #3220. If the statement
>>>> cites
>>>> components normatively the way Henri suggests, that's the published
>>>> home for
>>>> the rail-binding piece, under the same one-authority rule Nenad named.
>>>>
>>>> **Nenad's fourth vantage.**
>>>>
>>>> I think it's right and I'd add a note from our side. We have no
>>>> revocation, and
>>>> that's deliberate rather than missing: our grants carry an expiry, and
>>>> authority
>>>> decays without anyone needing to deliver anything. A suppressed
>>>> revocation is
>>>> invisible to a receiver, as you say — but you can't suppress the
>>>> passage of
>>>> time. It's a real trade, not a free win: a short expiry means
>>>> re-issuance
>>>> traffic and a live principal, and a long one means a wide window where
>>>> your
>>>> attack is exactly as bad as you describe. Where re-issuance is
>>>> affordable,
>>>> expiry is revocation you don't have to deliver, and I'd rather the
>>>> substrate
>>>> name that as an option than have every profile carry a revocation
>>>> channel it
>>>> can't guarantee reaches anyone.
>>>>
>>>> **Joel's fourth item.**
>>>>
>>>> Same answer as Henri, Pablo and Nenad: we don't have it. Nothing in our
>>>> records
>>>> pins the publisher-assigned version of any corpus a decision was
>>>> computed
>>>> against. Four for four is a better argument for lifting it into the
>>>> substrate
>>>> than any of us adding a field and then citing ourselves.
>>>>
>>>> **Willing, and here's what I bring.**
>>>>
>>>> The rail-enumeration binding above, the Coston2 fixtures, and the rung-3
>>>> refinement — anchor as pointer, not fact. Henri, the completeness
>>>> component and
>>>> its rungs stay yours to state; Todd, the fraud side is what keeps this
>>>> attached
>>>> to a real failure; and if Emek's ladder is going to carry the structure
>>>> of the
>>>> document, it should carry his name in it.
>>>>
>>>> Walter
>>>>
>>>> On Thu, Aug 20, 2026 04:53 PM, e.dogru@conarium.dev wrote:
>>>>
>>>>> Joel, Henri, Pablo, Walter, Todd, Nenad,
>>>>>
>>>>> Joel, you withdrew two claims in public before making your argument. I
>>>>> will put something of the same kind on the table before making mine.
>>>>>
>>>>> The corollary you name is the half I have not done, and I can show you
>>>>> exactly where the line falls.
>>>>>
>>>>> You wrote that the vocabulary has to reach the output, and that both
>>>>> our implementations skip it. In mine the /2 result carries a bounds object:
>>>>> for each bound the comparison relied on, its source is protocol-defined,
>>>>> measured, operator-declared, or undeclared, and a result whose bounds are
>>>>> operator-declared states an outcome of that standing and no stronger.
>>>>> Measured against the published package, one fixture, a receipt three
>>>>> seconds outside a two-hour window:
>>>>>
>>>>> - no profile: all three bounds undeclared, both items indeterminate
>>>>> - a profile with no clocks member: multiplicity and exclusion
>>>>> operator-declared, skew still undeclared
>>>>> - clocks.skew declared wider than the offset: operator-declared, and
>>>>> the item stays indeterminate. A declaration does not manufacture a match.
>>>>> - clocks.skew declared narrower than the offset: the same item becomes
>>>>> observed-without-receipt
>>>>>
>>>>> So the vocabulary reaches that object. It does not reach the exit
>>>>> codes, which predate it and are still not a mapping of it. Your sentence
>>>>> covers precisely the half I have not done, and I would rather that stayed
>>>>> in the record than get answered with a plan.
>>>>>
>>>>> The three clocks fields you asked for are in -05 with their encoding:
>>>>> clocks.observation, clocks.receipt, clocks.skew, a duration grammar, a rule
>>>>> that an unknown key in clocks is rejected by name, and a rule that the same
>>>>> bound declared twice must parse to the same milliseconds or the run fails
>>>>> rather than picking one. Written to be borrowed, not restated.
>>>>>
>>>>> On placement. The distinction is in -05 as a security consideration
>>>>> (sec-completeness), written against my own implementation rather than about
>>>>> two of them: a truncated receipt set verifies, detecting the removal needs
>>>>> a quantity from outside it, and whether that quantity reached the verifier
>>>>> independently of the Issuer is not visible in a digest. I support lifting
>>>>> it to the substrate, with one caveat about how it is worded there. The
>>>>> property that matters is not "in-record beats argument". It is that a
>>>>> Consumer cannot tell the two apart from the artefact, so the result has to
>>>>> say which one it relied on. Stated as a ranking it invites an
>>>>> implementation to claim the stronger form without carrying it; stated as a
>>>>> disclosure obligation it does not.
>>>>>
>>>>> On the weakest-rung rule. Four documents arriving at it separately is
>>>>> a better argument for the substrate than any one of us restating it, and
>>>>> your verdict-side version is the one I would take as the general form,
>>>>> because it survives translation to outputs that are not bounds at all. One
>>>>> caution from the side that has already shipped it: the rule is cheap to
>>>>> write and expensive to keep. indeterminate is only load-bearing while
>>>>> nobody is allowed to average it, and the pressure to fold it into a
>>>>> coverage percentage arrives from outside engineering, after the vocabulary
>>>>> is public and looks like a scoring system.
>>>>>
>>>>> One more thing worth putting in the record. Your sentence from two
>>>>> days ago, that a gaps section going stale understating an implementation
>>>>> fails the same way as one that overstates, turned out to apply to mine four
>>>>> times over. Each statement was accurate when written and false within days,
>>>>> always in the direction of claiming less than the code did, and nothing in
>>>>> my test suite compares that section against the code. So the corollary
>>>>> reaches further than either of us put it: the problem is not that our
>>>>> implementations skip the vocabulary. It is that neither of us has a check
>>>>> that would notice if they did. That is the gap I would most like the
>>>>> substrate to make expensive to leave open, and it is the next thing I write
>>>>> on my own side. I will come back with the check and what it caught, rather
>>>>> than with a plan.
>>>>>
>>>>> Emek Can Dogru
>>>>> Conarium
>>>>>
>>>>>
>>>>> On Fri, Aug 21, 2026 at 12:06 AM Joel Hillier <jhillier=
>>>>> 40certisyn.com@dmarc.ietf.org> wrote:
>>>>>
>>>>> Hi Henri, Pablo, Walter, Todd,
>>>>>
>>>>> Emek, I'm adding you to this because the rung ladder is yours and it's
>>>>> been travelling without your name on it. Henri's message this morning
>>>>> credits you with cloning at befdced and running the three cases,
>>>>> which is true, but you're also the one who wrote the ladder and the rule
>>>>> that goes with it. That rule is the most useful thing in this thread, and
>>>>> the first thing I did with it was turn it on my own document.It cost me two
>>>>> claims I made to you all yesterday. Both are below, before the rest.
>>>>>
>>>>> *Correction one. I told you ARP's sweep chain makes a withdrawn
>>>>> Statement detectable. That's true for the middle and false for the tail.*
>>>>>
>>>>> Each Evaluation Sweep Statement carries the previous Statement's
>>>>> notarisation, so I had the chain doing a job it can't do. Your 0.2.4
>>>>> shipped under "a hash chain is blind to a shorter tail" and it applies to
>>>>> my series exactly as it applies to yours: a truncatedtail of Sweep
>>>>> Statements verifies precisely as it did before.
>>>>>
>>>>> What actually puts ARP at rung 3 is a different mechanism, which I'd
>>>>> been crediting to the chain. Each Statement is due inside a bounded
>>>>> interval measured from its trigger, and where the trigger is a public event
>>>>> with a public timestamp, a sanctions list publishinga delta starts a clock
>>>>> the operator doesn't own. An operator with no Statement inside the interval
>>>>> hasn't evaluated in time, and anyone can check that holding none of the
>>>>> set. The chain covers the middle. The deadline covers the tail. Two
>>>>> mechanisms, and I'dhad them credited as one.
>>>>>
>>>>> *Correction two, and this one is worse, because it's the sentence
>>>>> where I congratulated myself on not rounding up.*
>>>>>
>>>>> I said the falsifiability argument holds for three of ARP's four
>>>>> triggers, "stated rather than rounded up." Only one of those three rested
>>>>> on anything outside the reconciliation server. The other two rested on a
>>>>> transition list published by the server, underthe server's own key, in a
>>>>> document with no publication time, no notarisation and no chain. A
>>>>> transition simply left out of that array started no clock, and no party
>>>>> could date the document well enough to show that it had been. On that
>>>>> footing the count wasone in four, and the sentence claiming otherwise was
>>>>> the one place the document rounded up.
>>>>>
>>>>> It's three in four now because I fixed the mechanism rather than the
>>>>> sentence: the document carries a publication timestamp, is notarised on the
>>>>> ledger-head interval, and has to be republished on that interval whether or
>>>>> not anything in it changed. That lastpart is the one that matters, and it's
>>>>> your placement argument doing the work. Without it, an operator that
>>>>> removed a witness entry and an operator that changed nothing publish the
>>>>> same thing, and the notarised series has no entry to be missing.
>>>>>
>>>>> The claim is now conditional and the document says so: a deployment
>>>>> whose policy parameters aren't anchored that way has one falsifiable
>>>>> trigger, not three. Which is your rule about naming the ground, applied to
>>>>> a count I'd already published.
>>>>>
>>>>> *One more, since it's the mechanism I described to Walter yesterday.*
>>>>> I said ARP's witness quorum counts entries under common control once,
>>>>> because two instances of one observer aren't two observers. The
>>>>> distinctness test was written over the operating-partyidentifier alone and
>>>>> said nothing about the keys. Two entries declaring the same key under two
>>>>> different party identifiers satisfied a quorum of two with a single
>>>>> signature. Both entries verify, the identifiers are distinct, and a relying
>>>>> party doing exactlywhat the document said counted one signer twice. Now
>>>>> fixed by requiring the verification method references to be pairwise
>>>>> distinct as well.
>>>>>
>>>>> Worth separating that from the limit I did state correctly. Whether
>>>>> two named parties are genuinely independent can't be tested by a verifier
>>>>> and the document concedes it. Whether two entries name one key can always
>>>>> be tested, and wasn't.
>>>>>
>>>>> *Now the thing I owe this thread.*
>>>>>
>>>>> Henri and Pablo have both said they'd need to add the fourth item
>>>>> before they could point at one, and Henri's suggested the substrate cite
>>>>> components normatively rather than restate them. Together that means the
>>>>> fourth item gets lifted out of ARP. So let mehand it over along with what
>>>>> was wrong with it, rather than after it's in shared text.
>>>>>
>>>>> A Partial Attestation carries a Source-Data Version Identifier Set:
>>>>> one identifier per source consulted in evaluating the predicate. Each is a
>>>>> tuple of the list name as declared in the bilateral agreement, and the
>>>>> state identifier the list publisher assignsto that state, not a value the
>>>>> answering party made up. It rides in the protected header so it's covered
>>>>> by the register's signature, and it's carried into the output so it's
>>>>> covered by the sealing signature.
>>>>>
>>>>> The reason it's the publisher's identifier and not the register's is
>>>>> the part worth carrying into any shared text, because it isn't obvious and
>>>>> it's the whole point. A register-chosen opaque string would be an
>>>>> arbitrary-bandwidth channel from register to relyingparty, travelling under
>>>>> signature into a sealed and ledgered artefact, and the accompanying rule
>>>>> that differing identifiers mustn't be read as disagreement would normalise
>>>>> it. Taking the identifier from the publisher's own state sequence is what
>>>>> makes it evidenceinstead of a side channel.
>>>>>
>>>>> Three things were wrong with the encoding, all found yesterday, all
>>>>> now repaired:
>>>>>
>>>>> 1. The Set had no ordering rule. Five other collections in ARP carry
>>>>> an explicit bytewise sort. This one was called a Set in its own section
>>>>> heading, was carried into two signatures, and was never sorted, so a
>>>>> register consulting three lists had six conformingencodings of one
>>>>> attestation. Now sorted.
>>>>>
>>>>> 2. The state identifier was disjunctive with no discriminator. "A
>>>>> published version token, or a digest of the published corpus where the
>>>>> publisher assigns none." Text in one branch, digest bytes in the other,
>>>>> same position, no algorithm named, and no statementof what the corpus is as
>>>>> a byte sequence. It now carries an explicit form discriminator, and the
>>>>> digest branch is taken over the octets the publisher serves, before any
>>>>> decompression. That second part is the one I'd have got wrong: a list
>>>>> published as a compressedarchive has at least two byte sequences with an
>>>>> equal claim to being the corpus, and two registers choosing differently
>>>>> produce two identifiers for one state, which a retroactive sweep then reads
>>>>> as a version change that never happened.
>>>>>
>>>>> 3. It was carried twice with no equality rule. ARP has exactly the
>>>>> right sentence for this, that a value carried twice with no equality rule
>>>>> is a value an implementation may read either way, and applied it to the two
>>>>> other duplicated headers and not to thisone.
>>>>>
>>>>> So the shape and the reason are worth lifting. The encoding is worth
>>>>> lifting as of this morning and wasn't yesterday.
>>>>>
>>>>> *On placement, Emek, your distinction deserves to be a named property
>>>>> of the substrate rather than a remark about two implementations.*
>>>>>
>>>>> You put it as: Henri's seal is a record inside the stream, signed and
>>>>> carried with the evidence, readable by whoever holds the set; Conarium's
>>>>> pin is an argument to the verifier, so a third party handed only the
>>>>> receipt set can't tell it's short unless someonestates what it should have
>>>>> been, and the obvious someone is the issuer, the party the audit is about.
>>>>>
>>>>> That's sharper than the rung number alone, because two mechanisms can
>>>>> sit on the same rung and differ entirely in who has to be asked. I'd state
>>>>> it as three placements:
>>>>>
>>>>> Inside the evidence. Travels with the set, needs nobody. Henri's seal.
>>>>>
>>>>> Supplied by the audited party. The verifier has to be told the
>>>>> expected count or terminal hash, and the party best placed to tell it is
>>>>> the one under audit. Conarium's pin, and you said so yourself rather than
>>>>> letting the symmetry flatter you.
>>>>>
>>>>> Supplied by a party with no stake. ARP's deadline is this one: the
>>>>> clock is started by a list publisher who's never heard of the
>>>>> reconciliation server.
>>>>>
>>>>> The third is strongest and least available, because it only exists
>>>>> where the obligation happens to be triggered by something public. It isn't
>>>>> a design choice you can make freely. Where it exists it should be used, and
>>>>> where it doesn't the statement should saywhich of the other two you're on.
>>>>>
>>>>> The sweep found a fourth case that the three-way split predicts and I
>>>>> hadn't looked for: a mechanism sitting at the first placement whose
>>>>> evidence is only obtainable from the second. ARP's head consistency
>>>>> statements are signed by independent witnesses, whichis the whole point of
>>>>> them, and the document specified the artefact, the quorum arithmetic and
>>>>> the freshness window and specified no channel by which a relying party
>>>>> obtains one. The obvious implementation is that the responding service
>>>>> hands them over withits response. Every check passes. The witness signature
>>>>> stops the service forging a statement and does nothing to stop it choosing
>>>>> which ones to pass on, so under exactly the fork the mechanism exists to
>>>>> detect, each branch's reader gets the witnesses thatbranch was fed. Now
>>>>> fixed by requiring witnesses to publish on their own origins and forbidding
>>>>> acceptance of one obtained from the responding service.
>>>>>
>>>>> Worth adding to the substrate as a rule in its own right: *state
>>>>> where the evidence is obtained, not only where it is produced.* An
>>>>> artefact produced at the third placement and delivered by the second is at
>>>>> the second.
>>>>>
>>>>> *Your weakest-rung rule already exists in ARP under another name,
>>>>> which I think argues it's the right general rule rather than a local
>>>>> convention.*
>>>>>
>>>>> You wrote that a result which doesn't say which rung it stands on has
>>>>> to be read at the weakest one, and that it's Walter's completeness ladder
>>>>> one level up.
>>>>>
>>>>> ARP arrived at the same rule from the verdict side and calls it
>>>>> verdict re-typing. An answer over a register whose attestation can't be
>>>>> verified doesn't produce a weaker match, it produces indeterminate.
>>>>> Where a re-notification can't say whether a change came from policy or from
>>>>> the underlying corpus, it has to carry attribution-indeterminate and
>>>>> name which causes were examined and why neither could be excluded, because
>>>>> a bare qualifier is a discretionary escape signed by the party that
>>>>> benefits from it. And conformance run records carry a
>>>>> does_not_establish field so the things a run didn't prove are
>>>>> enumerated rather than inferred from silence.
>>>>>
>>>>> Four instances, four documents, arrived at separately: bounds in
>>>>> yours, populations in Walter's, verdicts and conformance claims in mine.
>>>>> Worth stating once in the substrate, roughly as: *every result names
>>>>> the ground it stands on, and a result that names none is read at the
>>>>> weakest ground available to it.*
>>>>>
>>>>> The corollary is the one implementations skip, including both of ours.
>>>>> The vocabulary has to reach the output. You say your exit codes predate the
>>>>> vocabulary and still aren't a mapping of it. I found two of the same shape
>>>>> this week: a verifier told to refusea proof with no defined way to say
>>>>> which of four refusals it made, and one reason code carrying five distinct
>>>>> causes because four other sections pointed at it for conditions its own
>>>>> definition never named. Both now split. Defining the distinction and
>>>>> givingthe implementation no way to express it is a document agreeing with
>>>>> itself.
>>>>>
>>>>> *On your open question about the boundary declaration.*
>>>>>
>>>>> You framed it well: a boundary inside the record has nothing to drift
>>>>> from and is the stronger guarantee, but it's asserted by one party at issue
>>>>> time; a profile is the weaker binding and the only one that can be agreed
>>>>> between parties before a run and pointedat afterwards by both.
>>>>>
>>>>> ARP's answer is to make the profile a signed bilateral instrument with
>>>>> a hash. The agreement is settled before any run, both parties compute an
>>>>> agreement hash over its declared items independently and have to get the
>>>>> same value, and every reconciliation commitsto that hash. Drift suspends
>>>>> reconciliation rather than producing a weaker answer. So it keeps the
>>>>> agreed-not-asserted property of a profile and gains the
>>>>> nothing-to-drift-from property of an in-record boundary.
>>>>>
>>>>> The cost is that it only works bilaterally. It doesn't reach a
>>>>> population of parties who have never negotiated, which is most of Walter's
>>>>> setting. Worth having in the statement as one of the answers rather than
>>>>> the answer.
>>>>>
>>>>> *Pablo, your precedence point generalises, and it flips direction
>>>>> depending on what's being anchored.* Yours is anchoring_precedence:
>>>>> the anchor has to be strictly earlier than the outcome it covers, because
>>>>> an anchor arriving after the fact proves nothing about what was true when
>>>>> the outcome was recorded. ARP's is the mirror image. The Statement has
>>>>> tofall later than the trigger and inside a bounded interval, because what's
>>>>> being proved is that a duty was discharged on time, not that a fact was
>>>>> true beforehand.
>>>>>
>>>>> Same underlying requirement, that an anchor with no ordering
>>>>> constraint against the thing it covers is decorative. Two opposite
>>>>> orderings, because one anchors the proof and the other anchors the duty.
>>>>> I'd say it that way in the shared text: every external anchordeclares its
>>>>> required ordering relative to what it covers, and which of the two it is.
>>>>>
>>>>> Agreed on normative citation over restatement, with one addition.
>>>>> Where a component is cited rather than restated, the citing statement
>>>>> should also name the rung the component reaches. Henri's correction this
>>>>> morning is the case in point, and so are both ofmine above. None of the
>>>>> three components changed. The claim made about each was one rung short. A
>>>>> substrate that cites a component and repeats an over-broad claim about it
>>>>> has moved the error rather than removed it.
>>>>>
>>>>> Joel
>>>>>
>>>>>
>>>