<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE rfc [
  <!ENTITY nbsp    "&#160;">
  <!ENTITY zwsp   "&#8203;">
  <!ENTITY nbhy   "&#8209;">
  <!ENTITY wj     "&#8288;">
]>
<rfc xmlns:xi="http://www.w3.org/2001/XInclude" version="3" category="info" docName="draft-oga-musubi-settlement-00" ipr="trust200902" submissionType="IETF" xml:lang="en" tocInclude="true" sortRefs="true" symRefs="true">
<front>
<title abbrev="MUSUBI Settlement">MUSUBI Settlement: Recomputing Whether an Agent Acted Within a Signed Grant</title>
<seriesInfo name="Internet-Draft" value="draft-oga-musubi-settlement-00"/>
<author fullname="Toshikatsu Oga" initials="T." surname="Oga"><organization>The HORIZONs Co., Ltd.</organization><address><postal><country>Japan</country></postal><email>thehorizon.nnovation@icloud.com</email></address></author>
<date year="2026" month="October" day="17"/>
<keyword>settlement</keyword><keyword>agents</keyword><keyword>Ed25519</keyword><keyword>Bitcoin anchoring</keyword><keyword>canonical JSON</keyword>
<abstract>
<t>MUSUBI settlement is a deterministic function that takes a contract signed by two parties, a set of signed records of what an agent did under that contract, and a view of Bitcoin block headers, and computes whether the recorded acts stayed within the grant the contract gives. Anyone holding the same bytes can recompute the result without trusting the party that produced it. This document specifies one well defined part of that function, settle core v0, precisely enough that a second implementation can be written from the text and the published test vectors alone. Settlement is not runtime enforcement and is not a judgement of liability.</t>
</abstract>
</front>
<middle>
<section anchor="intro">
<name>Introduction</name>

<section anchor="what">
<name>What Settlement Is</name>
<t>A principal and a contractor sign a contract. The contract carries a grant: the actions the contractor is authorized to take, the actions it is prohibited from taking, the actions that need a separate approval from the principal, the parties to whom work may be delegated, an expiry height and a revocation policy. While the contractor (or a witness named in the grant) works, it signs records of what it did, and each record is committed to the Bitcoin block chain <xref target="BITCOIN"/> through an anchor. Later, anyone who holds the contract, the records and a view of the relevant block headers can settle: walk the records in the order the block chain gives them, compare each act with the grant, and produce a verdict, a status and a bond outcome.</t>
<t>The record schema names carry the prefix "a2a" because the format was designed for agents that interact over the Agent2Agent (A2A) protocol <xref target="A2A"/>. Settlement reads no A2A message and does not depend on A2A.</t>

</section>
<section anchor="why">
<name>Why a Second Implementation Needs a Text</name>
<t>Until this document, the MUSUBI settle function was defined only by Python code (settle_v1.py to settle_v1_16.py, each layer importing the ones below it) <xref target="MUSUBI-REF"/>. A function that only one program can compute is a tool, not a protocol. This document states one well defined part of it, settle core v0, in plain language. A stranger should be able to write a second implementation from this text and the vectors alone, without reading the reference.</t>
<t>The text was written from the reference code, not from intent. Writing it against settle_v1_10.py found places where the code accepted input a careful second implementation would read differently, and one place where a record nobody signed could change the verdict (items N1 to N11 of <xref target="MUSUBI-NOTES"/>). settle_v1_16.py was written to close them, and this document describes it. <xref target="written-behaviour"/> lists what changed. Where the reference still does something surprising, this document says so and marks it WRITTEN BEHAVIOUR. Written behaviour is still normative for core v0: a second implementation that differs on it will disagree with the vectors.</t>
<t>This document is an adaptation of <xref target="MUSUBI-SETTLE-CORE"/> into the Internet-Draft format. Where the two differ in meaning, that is an error in this document.</t>

</section>
<section anchor="not">
<name>What Settlement Is Not</name>
<t>Settlement is not runtime enforcement. It never stops an agent from acting; it reads records after the fact and says whether the recorded acts were within the grant.</t>
<t>Settlement is not a judgement of liability or fault, and it does not make the contract a legal contract. The verdict is a function anyone can recompute from the same bytes. <xref target="not-established"/> lists what the verdict does not establish.</t>

</section>
<section anchor="scope">
<name>Scope of Core v0</name>
<t>Settle core v0 is exactly what the reference computes when the contract carries none of the following:</t>
<ul>
<li><tt>requirements.spine</tt> (the spine gate, settle v1.8),</li>
<li><tt>requirements.convergence</tt> (drawn measurers, settle v1.9),</li>
<li><tt>grant.approval_policy.approvers</tt> (pinned approvers, settle v1.10),</li>
<li><tt>grant.limits</tt> (which forces <tt>requirements.admission</tt>),</li>
<li><tt>requirements.admission</tt> (settle v1.11 to v1.14 read it; the admissions input is passed through unchanged).</li>
</ul>
<t>It is computed in binding mode "strict" over exactly one header view.</t>
<t>Out of scope, and not defined here:</t>
<ul>
<li>choosing between several header views (fork choice by work above the checkpoint),</li>
<li>binding mode "legacy" (records bound by contract_id only),</li>
<li>fetching anything. Settle core v0 never touches the network. Every key it uses is inside the contract.</li>
</ul>
<t>If a contract carries any of the keys above, this document does not define the result. An implementation <bcp14>MUST NOT</bcp14> claim core v0 conformance for such an input.</t>

</section>
</section>
<section anchor="conventions">
<name>Conventions and Terminology</name>

<section anchor="bcp14">
<name>Requirements Language</name>
<t>The key words "<bcp14>MUST</bcp14>", "<bcp14>MUST NOT</bcp14>", "<bcp14>REQUIRED</bcp14>", "<bcp14>SHALL</bcp14>", "<bcp14>SHALL NOT</bcp14>", "<bcp14>SHOULD</bcp14>", "<bcp14>SHOULD NOT</bcp14>", "<bcp14>RECOMMENDED</bcp14>", "<bcp14>NOT RECOMMENDED</bcp14>", "<bcp14>MAY</bcp14>", and "<bcp14>OPTIONAL</bcp14>" in this document are to be interpreted as described in BCP 14 <xref target="RFC2119"/> <xref target="RFC8174"/> when, and only when, they appear in all capitals, as shown here.</t>
<t>Most rules in this document are stated in the indicative ("is", "gives", "adds"). They are normative all the same: they determine the core fields (<xref target="core-fields"/>) that a second implementation <bcp14>MUST</bcp14> reproduce exactly.</t>

</section>
<section anchor="terms">
<name>Terminology</name>
<dl newline="false">
<dt>contract:</dt><dd>A JSON object with schema <tt>a2a&nbhy;contract&nbhy;v0</tt>, signed by a principal and a contractor, that carries the grant.</dd>
<dt>principal, contractor:</dt><dd>The two parties to a contract, identified by their <tt>role</tt> and holding the Ed25519 <xref target="RFC8032"/> keys pinned in the contract.</dd>
<dt>witness:</dt><dd>A key named in <tt>grant.witnesses</tt> that may sign execution records.</dd>
<dt>record:</dt><dd>An execution (<tt>a2a&nbhy;execution&nbhy;v0</tt>), a revocation (<tt>a2a&nbhy;revocation&nbhy;v0</tt>) or a revocation acknowledgement (<tt>a2a&nbhy;revocation&nbhy;ack&nbhy;v0</tt>).</dd>
<dt>header view:</dt><dd>A list of raw 80 byte Bitcoin block headers <xref target="BITCOIN-HEADERS"/> with their heights.</dd>
<dt>walk:</dt><dd>A NENRIN walk record <xref target="NENRIN-VERIFIER"/> cited by an execution through <tt>nenrin_ref</tt>.</dd>
<dt>the reference:</dt><dd>settle_v1_16.py and the files it imports, at the versions listed in <xref target="impl-status"/> <xref target="MUSUBI-REF"/>.</dd>
<dt>WRITTEN BEHAVIOUR:</dt><dd>A behaviour of the reference that may surprise a reader, kept because the vectors pin it, or would.</dd>
<dt>integer:</dt><dd>A JSON value written as an integer token: no fraction, no exponent. <tt>true</tt> and <tt>false</tt> are never integers.</dd>
</dl>
<t>The following notation is used for byte strings. A string in double quotes, such as <tt>"a2a&nbhy;contract&nbhy;v0\n"</tt>, denotes the ASCII bytes between the quotes, where <tt>\n</tt> stands for one line feed (0x0A). When A and B are byte strings, <tt>A + B</tt> is their concatenation. <tt>sha256(x)</tt> is SHA-256 <xref target="FIPS180-4"/> of the bytes x. Byte ranges such as "bytes 4 to 36" are zero-based and exclude the upper bound, so they name the 32 bytes at offsets 4 through 35. "Lowercase hex" means the characters <tt>0</tt> to <tt>9</tt> and <tt>a</tt> to <tt>f</tt>, two per byte.</t>

</section>
</section>
<section anchor="shape">
<name>Inputs, Outputs and the Shape of the Computation</name>

<section anchor="inputs">
<name>Inputs</name>
<ol>
<li><tt>contract</tt>: one JSON object (schema <tt>a2a&nbhy;contract&nbhy;v0</tt>).</li>
<li><tt>events</tt>: a list of JSON values. Each is meant to be a record: an execution (<tt>a2a&nbhy;execution&nbhy;v0</tt>), a revocation (<tt>a2a&nbhy;revocation&nbhy;v0</tt>) or a revocation acknowledgement (<tt>a2a&nbhy;revocation&nbhy;ack&nbhy;v0</tt>). Anything else is ignored. Order carries no meaning.</li>
<li><tt>view</tt>: one JSON object <tt>{"headers": [{"height": H, "hex": "&lt;160 lowercase hex&gt;"}, ...]}</tt>, raw 80 byte Bitcoin block headers. Other keys are ignored.</li>
<li><tt>nenrin_records</tt>: optional list of JSON values (walk records cited by executions). Absent and empty mean the same thing. A value that is not a list is treated as absent.</li>
<li><tt>parent</tt>: optional, the parent contract, needed only when <tt>contract.parent_contract</tt> is present (<xref target="strict-terms"/>).</li>
</ol>
<t>If <tt>contract</tt> is not an object, the settlement is underspecified with the single reason <tt>contract_not_verified</tt>. If <tt>events</tt> is not a list, it is underspecified with <tt>input_not_settleable</tt>. Nothing else is computed in either case.</t>
<t>Keys are not a separate input. The principal's and contractor's Ed25519 public keys are <tt>parties[i].public_key_ed25519_b64</tt> inside the contract, and witness keys are <tt>grant.witnesses[i].public_key_ed25519_b64</tt>. <tt>key_url</tt> is never fetched. Checking that the key served at <tt>key_url</tt> equals the pinned key is outside settle core.</t>

</section>
<section anchor="reading-json">
<name>Reading JSON</name>
<t>Inputs are parsed as JSON <xref target="RFC8259"/> with one extra rule: an object with a duplicate key is an error and no settlement is produced. Text nested deeper than 512 levels of <tt>[</tt> or <tt>{</tt> (counted outside strings) is also an error.</t>
<t>Numbers <bcp14>MUST</bcp14> be integers within plus or minus (2^53 - 1). The contract is checked for this in <xref target="contract-door"/>, records in <xref target="triage"/>, the view in <xref target="view-verify"/> and walks in <xref target="nenrin"/>. A JSON value with a non-integer number is not "strict" in the sense of <xref target="triage"/>.</t>
<t>A JSON value is an "integer" in this document only if it is written as an integer token: no fraction, no exponent. <tt>true</tt> and <tt>false</tt> are never integers.</t>
<t>These rules are close to, but not the same as, I-JSON <xref target="RFC7493"/>.</t>

</section>
<section anchor="computation">
<name>The Computation in One Paragraph</name>
<t>Compute contract_sha256 (<xref target="digests"/>) and bind records by it (<xref target="binding"/>). Triage every bound record (<xref target="triage"/>): records not strictly signed by a party are rejected or set aside here, and no later step sees them. Check the contract's terms (<xref target="contract"/>) and verify the header view (<xref target="view"/>). Every problem found so far is collected; none of them stops the other checks in this paragraph. If a problem was found in <xref target="contract-door"/>, <xref target="settleable-terms"/> or rules 1 to 8 of <xref target="view-verify"/>, no record is examined further. Otherwise: collapse copies of one signed body (<xref target="collapse"/>), check conformance (<xref target="conformance"/>), check anchors (<xref target="anchors"/>). Records that pass are the event set, ordered by anchor height then record sha256 (<xref target="event-set"/>). Walk the event set against the grant (<xref target="grant"/>), add the NENRIN checks (<xref target="nenrin"/>), and decide the verdict (<xref target="verdict"/>), status (<xref target="status"/>) and bond outcome (<xref target="bond-outcome"/>). The checks of <xref target="strict-terms"/>, rule 9 of <xref target="view-verify"/>, <xref target="triage"/> (a record that fails closed), <xref target="anchor-block"/> (below the lower bound) and <xref target="nenrin"/> (a cited walk) are collected in the same way and make the settlement underspecified; they never stop the computation of the event set.</t>

</section>
<section anchor="output-overview">
<name>Output</name>
<t>The output is one JSON object. <xref target="output"/> lists the core fields a second implementation <bcp14>MUST</bcp14> reproduce exactly. Everything else the reference writes is informative.</t>

</section>
</section>
<section anchor="crypto">
<name>Canonical Form, Digests and Signatures</name>

<section anchor="canonical">
<name>Canonical JSON (musubi-canonical-v0)</name>
<t><tt>canonical(v)</tt> is the UTF-8 <xref target="RFC3629"/> encoding of this text:</t>
<ol>
<li>Objects: keys sorted by Unicode code point, at every level. Written <tt>{"k":v,...}</tt> with no whitespace.</li>
<li>Arrays: <tt>[a,b,...]</tt> with no whitespace.</li>
<li>Strings: written between <tt>"</tt>. Escape only <tt>"</tt> as <tt>\"</tt>, <tt>\</tt> as <tt>\\</tt>, and U+0000 to U+001F. Of those, U+0008 is <tt>\b</tt>, U+000C is <tt>\f</tt>, U+000A is <tt>\n</tt>, U+000D is <tt>\r</tt>, U+0009 is <tt>\t</tt>, and the rest are <tt>\u00xx</tt> with lowercase hex. Every other character is written as itself, including U+007F, U+2028, U+2029 and all non-ASCII. A lone surrogate code unit (U+D800 to U+DFFF not part of a valid pair) is written <tt>\udxxx</tt> with lowercase hex.</li>
<li>Integers: decimal, <tt>&nbhy;</tt> only for negatives, no leading zeros, no fraction, no exponent.</li>
<li><tt>true</tt>, <tt>false</tt>, <tt>null</tt> as literals.</li>
</ol>
<t>The reference ships fixed inputs for this rule (musubi-v0/canonical_vectors.json) and a Node twin (canonical_v0.mjs) <xref target="MUSUBI-REF"/>.</t>
<t>This form is not the JSON Canonicalization Scheme <xref target="RFC8785"/>. Among other differences, RFC 8785 sorts keys by UTF-16 code units, which gives a different order for keys with characters above U+FFFF, and serializes non-integer numbers, which this form never writes.</t>

</section>
<section anchor="base64-keys">
<name>Base64 and Keys</name>
<t>Base64 is standard base64 (<xref target="RFC4648" section="4" sectionFormat="of"/>) with padding, and <bcp14>MUST</bcp14> be canonical: decoding then re-encoding gives the same text. A public key is 32 bytes after decoding, a signature 64 bytes. Any other length, any non-canonical text, or any non-string is "unusable".</t>
<t>A public key is also unusable if it is not the canonical encoding of a point on edwards25519, if it is the identity point, or if the point is not in the prime order subgroup (small order or mixed order points).</t>

</section>
<section anchor="digests">
<name>The Digests</name>
<table>
<name>Digests</name>
<thead><tr><th align="left">name</th><th align="left">definition</th></tr></thead>
<tbody>
<tr><td align="left">contract signing bytes</td><td align="left"><tt>"a2a&nbhy;contract&nbhy;v0\n" + canonical(contract without its "signatures" key)</tt></td></tr>
<tr><td align="left">contract_sha256</td><td align="left">lowercase hex sha256 of the contract signing bytes</td></tr>
<tr><td align="left">record_sha256</td><td align="left">lowercase hex sha256 of <tt>canonical(record)</tt>, the whole record including <tt>anchor</tt> and <tt>signatures</tt></td></tr>
<tr><td align="left">body digest</td><td align="left">sha256 of <tt>canonical(record without its "anchor" key)</tt>. It includes <tt>signatures</tt>. Anchor proofs start from these 32 bytes</td></tr>
<tr><td align="left">record signing bytes</td><td align="left">context + <tt>canonical(record without "signatures" and without "anchor")</tt>. Context is <tt>"a2a&nbhy;execution&nbhy;v0\n"</tt>, <tt>"a2a&nbhy;revocation&nbhy;v0\n"</tt> or <tt>"a2a&nbhy;revocation&nbhy;ack&nbhy;v0\n"</tt> by the record's schema</td></tr>
</tbody></table>
<t>contract_sha256 is the identity of the terms. It does not change when a signature is added. A record is bound to a contract only by it (<xref target="binding"/>).</t>

</section>
<section anchor="ed25519">
<name>Ed25519 Verification</name>
<t><tt>verify(pub_b64, sig_b64, message)</tt> returns one of: true, false, unusable. It returns unusable when the key or signature fails <xref target="base64-keys"/>. Otherwise it is Ed25519 verification (<xref target="RFC8032"/>) of the 64 byte signature over the message bytes. The reference uses the Python <tt>cryptography</tt> package (OpenSSL). See item N9 of <xref target="MUSUBI-NOTES"/> on libraries that differ for adversarial signatures.</t>
<t>A 64 byte signature is "strict" when its last 32 bytes, read as a little-endian integer S, are below the group order L = 2^252 + 27742317777372353535851937790883648493, and its first 32 bytes R pass the public key test of <xref target="base64-keys"/> (a canonical encoding of a point of prime order, not the identity). "Strictly verifies" means the signature is strict and verify returned true. Libraries that disagree on lax signatures all agree on strict ones.</t>
<t>Everywhere below, "verifies" means verify returned true. False and unusable are both "does not verify", except in the contract door (<xref target="contract-door"/>), which names them differently.</t>

</section>
</section>
<section anchor="contract">
<name>The Contract</name>

<section anchor="contract-door">
<name>The Contract Door (Contract Verification)</name>
<t>The contract is accepted only if every check below passes. Any failure gives the single underspecified reason <tt>contract_not_verified</tt> (<xref target="settleable-terms"/> is then skipped). The reference reports a list of refusal codes alongside; those codes are informative. Only <tt>contract_not_verified</tt> is core.</t>
<ol>
<li><tt>schema</tt> is <tt>"a2a&nbhy;contract&nbhy;v0"</tt>.</li>
<li><tt>contract_id</tt> and <tt>nonce</tt> are each 32 lowercase hex characters.</li>
<li><tt>parties</tt> is a list of exactly two objects whose <tt>role</tt> values are exactly one <tt>"principal"</tt> and one <tt>"contractor"</tt>.</li>
<li>Each party's <tt>domain</tt> normalizes to a bare hostname: lowercase, outer spaces and one or more trailing dots removed, no <tt>/</tt>, <tt>@</tt>, <tt>:</tt> or space, at least two labels, each label matching <tt>^[a&nbhy;z0&nbhy;9]([a&nbhy;z0&nbhy;9&nbhy;]*[a&nbhy;z0&nbhy;9])?$</tt>. The two normalized domains differ.</li>
<li>Each party's <tt>key_url</tt> is an <tt>https://</tt> URL. (Whether its host is under the domain is a finding, not a refusal.)</li>
<li>Each party's <tt>public_key_ed25519_b64</tt> decodes as canonical base64 to 32 bytes. (The point check of <xref target="base64-keys"/> is applied later, when signatures are verified.)</li>
<li><tt>task</tt> is an object with a non-empty string <tt>purpose</tt>. <tt>task.payload_digest</tt>, when present and not null, is 64 lowercase hex.</li>
<li><tt>grant</tt> is an object. Its keys are only: <tt>authorized_actions</tt>, <tt>prohibited_actions</tt>, <tt>conditional</tt>, <tt>delegation</tt>, <tt>data_access</tt>, <tt>max_hops</tt>, <tt>privacy</tt>, <tt>revocation</tt>, <tt>finality</tt>, <tt>witnesses</tt>, <tt>expiry_height</tt>, <tt>ordering</tt>, <tt>approval_policy</tt>, <tt>limits</tt>. Any other key refuses the contract.</li>
<li><tt>grant.authorized_actions</tt> and <tt>grant.prohibited_actions</tt> are both lists of non-empty strings, and no action is in both.</li>
<li><t>Typed grant keys, each checked only when present and not null:</t>
<ul>
<li><tt>data_access</tt>: list of non-empty strings.</li>
<li><tt>max_hops</tt>, <tt>expiry_height</tt>: integer &gt;= 0.</li>
<li><tt>delegation</tt>: object whose only key is <tt>allowed</tt>, a list of non-empty strings.</li>
<li><tt>conditional</tt>: list of objects, each with a non-empty string <tt>action</tt>; actions unique; <tt>requires</tt>, when present, a string.</li>
<li><tt>finality</tt>: object with keys only from <tt>depth</tt>, <tt>max_target_bits</tt>. <tt>depth</tt>, when present, integer &gt;= 1. <tt>max_target_bits</tt>, when present, 8 lowercase hex that decodes (<xref target="compact-target"/>) to a positive target.</li>
<li><tt>witnesses</tt>: list of objects, each with a non-empty string <tt>name</tt> and a <tt>public_key_ed25519_b64</tt> that decodes to 32 bytes.</li>
<li><tt>privacy</tt>: non-empty string.</li>
<li><tt>ordering</tt>: object whose only key is <tt>same_height</tt>, a string or null.</li>
<li><tt>approval_policy</tt>: object with keys only from <tt>allow_unscoped</tt> (boolean) and <tt>approvers</tt> (out of scope, <xref target="scope"/>).</li>
<li><tt>revocation</tt>: an object whose <tt>effective_at</tt> is <tt>"anchor"</tt> or <tt>"delivery_ack"</tt>, with keys only from <tt>effective_at</tt>, <tt>ack_window</tt>; <tt>ack_window</tt>, when present, integer &gt;= 1.</li>
</ul></li>
<li>No number anywhere in the contract (signatures included) is a non-integer, NaN, an infinity, or an integer outside plus or minus (2^53 - 1).</li>
<li>Every object key anywhere in the contract is printable ASCII (U+0020 to U+007E).</li>
<li><tt>establishes</tt> is a non-empty list. No string in it matches, case-insensitively, any of the patterns listed after this list.</li>
<li><tt>does_not_establish</tt> is a non-empty list. Lowercased, its strings together contain: one of <tt>runtime</tt> or <tt>enforce</tt>; one of <tt>judge</tt>, <tt>liability</tt> or <tt>fault</tt>; <tt>deviat</tt>; and <tt>legal</tt>. Each of the four groups must be hit by at least one string.</li>
<li><tt>signatures</tt> is a list. For each object in it: its <tt>domain</tt> normalizes (rule 4) to a party's normalized domain, or the contract is refused. Its <tt>signature</tt> is verified (<xref target="ed25519"/>) with that party's key over the contract signing bytes. False or unusable refuses the contract, even if the same party also has a good signature (WRITTEN BEHAVIOUR). <tt>alg</tt> is not read.</li>
<li>Each party has at least one signature that verifies.</li>
</ol>
<t>The patterns of rule 13, one per line, are:</t>
<figure><name>Patterns refused in establishes</name><artwork type="ascii-art"><![CDATA[
\bperformed\b
\bdeliver(ed|y)\b
\bmoney (moved|was sent)\b
\bfunds? (moved|were sent|were transferred)\b
\bpaid\b(?!\s+for\s+(this|the)\s+record)
\bpayment (was|has been) (made|completed|settled|received)\b
\bcontract\b
\bbinding\b
\bguarantee
\bescrow\b
\bcustody\b
\bsolvent\b
\blawful\b
\bfair\b
\bcertified\b
]]></artwork></figure>
<t>Not read by the door, and not read anywhere in core v0: <tt>expiry</tt> (a wall clock), <tt>agreed_at</tt>, <tt>requirements.recovery</tt>, <tt>selection_provenance</tt>, <tt>liability_boundary</tt>, <tt>settlement</tt>. <tt>lower_bound</tt> is not checked here; <xref target="view"/> checks it. <tt>requirements.evidence</tt> is read in <xref target="nenrin"/>, <tt>bond</tt> and <tt>parent_contract</tt> in <xref target="strict-terms"/>.</t>

</section>
<section anchor="settleable-terms">
<name>Settleable Terms</name>
<t>Only when <xref target="contract-door"/> accepts, each of these adds the underspecified reason shown:</t>
<table>
<name>Settleable terms</name>
<thead><tr><th align="left">condition</th><th align="left">reason</th></tr></thead>
<tbody>
<tr><td align="left"><tt>grant.authorized_actions</tt> is not a list</td><td align="left"><tt>authorized_actions_missing</tt></td></tr>
<tr><td align="left">an action name in <tt>authorized_actions</tt>, <tt>prohibited_actions</tt> or <tt>conditional[].action</tt> does not match <tt>^[a&nbhy;z][a&nbhy;z0&nbhy;9_.:&nbhy;]{0,63}$</tt> (see <xref target="written-behaviour"/> and item N1 of <xref target="MUSUBI-NOTES"/>)</td><td align="left"><tt>grant_action_name_invalid</tt></td></tr>
<tr><td align="left">more than 32 witnesses</td><td align="left"><tt>too_many_witnesses</tt></td></tr>
<tr><td align="left">a witness key does not decode to 32 bytes</td><td align="left"><tt>witness_key_invalid</tt></td></tr>
<tr><td align="left">two witnesses share a name, or any two of {principal key, contractor key, each witness key} decode to the same 32 bytes</td><td align="left"><tt>key_conflict</tt></td></tr>
<tr><td align="left"><tt>grant.ordering.same_height</tt> is present and is neither null nor <tt>"conservative"</tt></td><td align="left"><tt>tie_policy_refused</tt></td></tr>
<tr><td align="left"><tt>grant.revocation</tt> is an object and <tt>effective_at</tt> is not <tt>"anchor"</tt> or <tt>"delivery_ack"</tt></td><td align="left"><tt>revocation_policy_not_recomputable</tt></td></tr>
<tr><td align="left"><tt>effective_at</tt> is <tt>"delivery_ack"</tt> and <tt>ack_window</tt> is not an integer &gt;= 1</td><td align="left"><tt>ack_window_missing</tt></td></tr>
<tr><td align="left"><tt>grant.finality.depth</tt> is not an integer &gt;= 1 (including a missing <tt>finality</tt> or <tt>depth</tt>)</td><td align="left"><tt>finality_policy_missing</tt></td></tr>
<tr><td align="left"><tt>grant.expiry_height</tt> is present, not null, and not an integer &gt;= 0</td><td align="left"><tt>bad_expiry_height</tt></td></tr>
<tr><td align="left"><tt>allow_unscoped</tt> in <tt>grant.approval_policy</tt> is truthy</td><td align="left"><tt>unscoped_approvals_refused</tt></td></tr>
</tbody></table>
<t>An empty <tt>authorized_actions</tt> list means nothing is authorized. It is not an error.</t>

</section>
<section anchor="strict-terms">
<name>Strict Terms</name>
<t>Whether or not <xref target="contract-door"/> accepts, each of these adds the underspecified reason shown:</t>
<table>
<name>Strict terms</name>
<thead><tr><th align="left">condition</th><th align="left">reason</th></tr></thead>
<tbody>
<tr><td align="left">a <tt>signatures[].signature</tt> decodes to 64 bytes and is not strict (<xref target="ed25519"/>)</td><td align="left"><tt>contract_signature_not_strict</tt></td></tr>
<tr><td align="left"><tt>bond</tt> is present and not null, and is not an object whose <tt>amount</tt> is an integer from 1 to 2^53 - 1 (<tt>true</tt> is not an integer)</td><td align="left"><tt>bond_malformed</tt></td></tr>
<tr><td align="left"><tt>parent_contract</tt> is present and not null, and no parent was supplied</td><td align="left"><tt>parent_not_supplied</tt></td></tr>
<tr><td align="left"><tt>parent_contract</tt> is present and not null, and the parent is not an object, or does not pass <xref target="contract-door"/> on its own, or the contract does not pass <xref target="contract-door"/> with the parent supplied (the reference's door then also checks that <tt>parent_contract.contract_id</tt> equals the parent's <tt>contract_id</tt> and that the child's grant is a subset of the parent's: <tt>contract_v0.grant_subset</tt>)</td><td align="left"><tt>parent_narrowing_failed</tt></td></tr>
</tbody></table>
<t>These checks do not stop the walk; the event set and dispositions are still computed (<xref target="computation"/>). The vectors show the subset rule with one widening (an added authorized action). A full statement of <tt>grant_subset</tt> is left to a later version of this document; until then, the reference's <tt>grant_subset</tt> (in contract_v0.py beside the reference <xref target="MUSUBI-REF"/>) is normative.</t>

</section>
</section>
<section anchor="view">
<name>The Header View</name>

<section anchor="view-verify">
<name>Verifying the View</name>
<t>The view is checked under two contract terms: the difficulty floor <tt>grant.finality.max_target_bits</tt> and the checkpoint <tt>lower_bound</tt> (<tt>height</tt>, <tt>hash</tt>). Any failure below gives the underspecified reason <tt>chain_view_rejected</tt>. The view is checked even when <xref target="contract"/> already failed.</t>
<ol>
<li><tt>grant.finality.max_target_bits</tt> is 8 lowercase hex and decodes (<xref target="compact-target"/>) to a target, the floor.</li>
<li><tt>lower_bound</tt> is an object with an integer <tt>height</tt> and a 64 lowercase hex <tt>hash</tt>.</li>
<li><tt>view.headers</tt> is a non-empty list.</li>
<li>Each header is an object with an integer <tt>height</tt> &gt;= 0 and a <tt>hex</tt> of 160 lowercase hex characters, optionally followed by one line feed (WRITTEN BEHAVIOUR of the lower layers; rule 9 below then refuses the line feed under its own reason).</li>
<li>Heights are consecutive in list order: each is the previous plus one.</li>
<li>From the second header on, bytes 4 to 36 of the header, reversed, as hex, equal the previous header's hash.</li>
<li>The header's own nBits (bytes 72 to 76, little-endian unsigned 32 bit) decode to a target; that target is not above the floor; the header hash read as a big-endian 256 bit number is not above that target.</li>
<li>The view holds a header at <tt>lower_bound.height</tt> whose hash equals <tt>lower_bound.hash</tt>.</li>
</ol>
<t>The header hash is sha256(sha256(80 raw bytes)), byte-reversed, as lowercase hex (the usual display order). The merkle root used by anchors (<xref target="anchor-proof"/>) is bytes 36 to 68 of the raw header, not reversed. The tip is the height of the last header. The view may start below the checkpoint. The first header's previous-hash field is not checked. Consensus rules beyond these (retargeting, timestamps, transactions) are not checked.</t>
<ol start="9">
<li>Separately, every header is an object with an integer <tt>height</tt> and a <tt>hex</tt> of exactly 160 lowercase hex characters, and every string, key and number in the view is strict (first paragraph of <xref target="triage"/>). If not, the reason <tt>view_not_strict</tt> is added. A header in upper case therefore gives both <tt>chain_view_rejected</tt> and <tt>view_not_strict</tt>; one that ends in a line feed gives only <tt>view_not_strict</tt>. Rule 9 does not stop the walk.</li>
</ol>
<t>If the view verifies but holds more than 200000 headers, the reason is <tt>input_too_large</tt> instead, and no record is examined.</t>

</section>
<section anchor="compact-target">
<name>Compact Target Decoding</name>
<t>For a 32 bit value <tt>bits</tt>: <tt>exp = bits &gt;&gt; 24</tt>, <tt>mant = bits &amp; 0x007fffff</tt>. If <tt>bits &amp; 0x00800000</tt> is set, or <tt>mant</tt> is 0, there is no target (invalid). Otherwise the target is <tt>mant &lt;&lt; (8 * (exp &nbhy; 3))</tt> when <tt>exp &gt;= 3</tt>, else <tt>mant &gt;&gt; (8 * (3 &nbhy; exp))</tt>.</t>

</section>
</section>
<section anchor="records">
<name>Records Before Their Anchors</name>

<section anchor="triage">
<name>Strict Records and Triage</name>
<t>A JSON value is strict when, at every depth up to 512 levels: every string and every object key is free of U+0000 to U+001F and U+007F; every key is ASCII; every number is an integer within plus or minus (2^53 - 1). A value nested deeper is not strict.</t>
<t>A record's parts:</t>
<ul>
<li>the body: the record without <tt>signatures</tt> and <tt>anchor</tt>. This is what its signers signed (<xref target="digests"/>, record signing bytes).</li>
<li>the anchor: <tt>anchor</tt>. Nobody signed it.</li>
<li>the signatures list: <tt>signatures</tt>. Nobody signed it either.</li>
</ul>
<t>The body is not strict when the body as a value is not strict, or (when present) <tt>nenrin_ref</tt> is neither null nor 64 lowercase hex, or <tt>contract_ref.contract_sha256</tt> or <tt>contract_ref.payload_digest</tt> is present and not 64 lowercase hex, or, for an execution: <tt>performed_actions</tt> or <tt>delegated_to</tt> is present and not a list of strings; <tt>approvals</tt> is present and not a list of objects; or an approval's <tt>sig_b64</tt> (or <tt>signature</tt>) decodes to 64 bytes and is not strict (<xref target="ed25519"/>).</t>
<t>The anchor is not strict when it is present and: it is not strict as a value; or its <tt>block_hash</tt> is present and not exactly 64 lowercase hex; or a proof operation's <tt>hex</tt> is present and is not exactly pairs of lowercase hex digits (the empty string is allowed).</t>
<t>A record is strictly signed when one entry of <tt>signatures</tt> has a role its schema allows (<xref target="authentication"/>), a signature that strictly verifies (<xref target="ed25519"/>) with the matching key over the record signing bytes, and is itself a strict value.</t>
<t>First, a record of one of the three schemas whose record_sha256 cannot be computed at all (for example an integer too long to write out) is set aside with reason <tt>record_not_strict</tt>. The others are bound (<xref target="binding"/>). Each bound record is then triaged, in this order:</t>
<table>
<name>Triage</name>
<thead><tr><th align="left">condition</th><th align="left">result</th></tr></thead>
<tbody>
<tr><td align="left">not strictly signed, body not strict</td><td align="left">set aside, <tt>record_not_strict</tt></td></tr>
<tr><td align="left">not strictly signed, but a signature verifies under <xref target="ed25519"/> alone (lax)</td><td align="left">set aside, <tt>signature_not_strict</tt></td></tr>
<tr><td align="left">not strictly signed otherwise</td><td align="left">rejected (disposition <tt>rejected</tt>)</td></tr>
<tr><td align="left">strictly signed, body not strict</td><td align="left">the record is a party's own statement: underspecified reason <tt>record_not_strict</tt></td></tr>
<tr><td align="left">strictly signed, anchor not strict, and another bound record with the same record signing bytes is kept by this table and anchors validly (<xref target="collapse"/>)</td><td align="left">set aside, <tt>anchor_not_strict</tt></td></tr>
<tr><td align="left">strictly signed, anchor not strict, otherwise</td><td align="left">underspecified reason <tt>anchor_not_strict</tt></td></tr>
<tr><td align="left">a revocation, and <tt>grant.revocation</tt> is not an object</td><td align="left">set aside, <tt>revocation_not_provided_for</tt> (the contract cannot be revoked)</td></tr>
<tr><td align="left">otherwise</td><td align="left">kept</td></tr>
</tbody></table>
<t>Set aside and rejected records are never examined again: no collapse (<xref target="collapse"/>), size limit (<xref target="size-limit"/>), conformance check, anchor check or NENRIN check sees them. They are listed with their disposition (<xref target="dispositions"/>). Problems in the signatures list of a strictly signed record (an extra entry that does not verify or is not strict) are ignored.</t>
<t>A third party holding copies of genuine records can change their anchors and signature lists but not their bodies. The table is arranged so that such copies are set aside or rejected whenever the genuine record is in the input.</t>

</section>
<section anchor="binding">
<name>Binding</name>
<t>Let <tt>cid = contract.contract_id</tt>, <tt>pdg = contract.task.payload_digest</tt> (it may be absent), <tt>csha = contract_sha256</tt>. Walk <tt>events</tt> in the given order. Skip anything that is not an object, or whose <tt>schema</tt> is not one of the three record schemas. Skip a record whose record_sha256 was already seen (identical bytes are one record). Then, with <tt>ref = contract_ref</tt> if it is an object, else empty:</t>
<table>
<name>Binding</name>
<thead><tr><th align="left">condition, in this order</th><th align="left">class</th></tr></thead>
<tbody>
<tr><td align="left"><tt>ref.contract_sha256</tt> absent or null, and <tt>ref.contract_id == cid</tt></td><td align="left">unbound (not settled in strict mode)</td></tr>
<tr><td align="left"><tt>ref.contract_sha256</tt> absent or null otherwise</td><td align="left">not ours: dropped silently</td></tr>
<tr><td align="left"><tt>ref.contract_sha256</tt> is not 64 lowercase hex</td><td align="left">inconsistent</td></tr>
<tr><td align="left"><tt>ref.contract_sha256 != csha</tt></td><td align="left">foreign</td></tr>
<tr><td align="left"><tt>ref.contract_id != cid</tt></td><td align="left">inconsistent</td></tr>
<tr><td align="left"><tt>pdg</tt> is present and not null, and <tt>ref.payload_digest != pdg</tt></td><td align="left">inconsistent</td></tr>
<tr><td align="left">otherwise</td><td align="left">bound</td></tr>
</tbody></table>
<t>Only bound records go further. Foreign, inconsistent and unbound records are listed (<xref target="output"/>) and never settled. Binding runs even when <xref target="contract"/> or <xref target="view"/> failed; its classes are then still reported. Binding is by <tt>contract_sha256</tt> alone, so a record made under earlier terms with the same <tt>contract_id</tt> is foreign and is never triaged (<xref target="triage"/>).</t>

</section>
<section anchor="size-limit">
<name>Size Limit</name>
<t>If more than 10000 records are kept by <xref target="triage"/>, the reason <tt>input_too_large</tt> is added and no record is examined further.</t>

</section>
<section anchor="identical-bytes">
<name>Identical Bytes</name>
<t>Two inputs with the same record_sha256 are one record. Supplying a record twice changes nothing.</t>

</section>
<section anchor="collapse">
<name>Several Copies of One Signed Body</name>
<t>The same signed body can reach the input more than once: anchored twice (two calendars, two batches), or with another <tt>signatures</tt> list. These copies differ only in their unsigned parts. Group the records kept by <xref target="triage"/> by their record signing bytes (<xref target="digests"/>). In a group with more than one distinct record_sha256:</t>
<ul>
<li>A copy "anchors validly" if: its <tt>anchor.height</tt> is an integer &gt;= 0 that the view holds; <tt>anchor.block_hash</tt> equals the view's hash at that height; the proof (<xref target="anchor-proof"/>) reaches that block's merkle root; and the batch leg rule (<xref target="batch-leg"/>) accepts it.</li>
<li>If at least one copy anchors validly, keep the one with the smallest (height, record_sha256) and drop the others. Dropped copies are listed (disposition <tt>duplicate_dropped</tt>).</li>
<li>If none does, keep them all. Each is then examined on its own.</li>
</ul>
<t>This is done when rules 1 to 8 of <xref target="view-verify"/> passed, whether or not <xref target="contract"/> did. Note that "anchors validly" does not compare the height with the checkpoint (see item N7 of <xref target="MUSUBI-NOTES"/>).</t>

</section>
<section anchor="authentication">
<name>Authentication</name>
<t>Authentication is part of <xref target="triage"/>: only strictly signed records are kept. The roles and keys are:</t>
<table>
<name>Signers by schema</name>
<thead><tr><th align="left">schema</th><th align="left">signer it needs</th><th align="left">key</th></tr></thead>
<tbody>
<tr><td align="left">a2a-execution-v0</td><td align="left">a signature with <tt>role</tt> <tt>"contractor"</tt>, or with <tt>role</tt> <tt>"witness"</tt> and a <tt>witness_name</tt></td><td align="left">the contractor's party key, or the key of the grant witness with that exact name</td></tr>
<tr><td align="left">a2a-revocation-v0</td><td align="left"><tt>role</tt> <tt>"principal"</tt></td><td align="left">the principal's party key</td></tr>
<tr><td align="left">a2a-revocation-ack-v0</td><td align="left"><tt>role</tt> <tt>"contractor"</tt></td><td align="left">the contractor's party key</td></tr>
</tbody></table>
<t><tt>signatures</tt> must be a non-empty list. Each entry is an object with <tt>role</tt>, <tt>sig_b64</tt> and, for a witness, <tt>witness_name</tt>. An entry with another role, or one that does not strictly verify, is skipped.</t>
<t>Then, for a kept revocation: if its <tt>revoked_by</tt> field is not <tt>"principal"</tt>, it is ignored (disposition <tt>ignored</tt>), even though the principal signed it.</t>

</section>
<section anchor="conformance">
<name>Conformance</name>
<t>Allowed top-level fields:</t>
<ul>
<li>execution: <tt>schema</tt>, <tt>contract_ref</tt>, <tt>performed_actions</tt>, <tt>approvals</tt>, <tt>delegated_to</tt>, <tt>nenrin_ref</tt>, <tt>outcomes</tt>, <tt>anchor</tt>, <tt>signatures</tt>,</li>
<li>revocation: <tt>schema</tt>, <tt>contract_ref</tt>, <tt>revoked_by</tt>, <tt>anchor</tt>, <tt>signatures</tt>,</li>
<li>acknowledgement: <tt>schema</tt>, <tt>contract_ref</tt>, <tt>revocation_sha256</tt>, <tt>acked_by</tt>, <tt>anchor</tt>, <tt>signatures</tt>.</li>
</ul>
<t>A record has a conformance problem if:</t>
<ul>
<li>it has a field outside its list,</li>
<li>(execution) <tt>performed_actions</tt> is not a list of strings,</li>
<li>(execution) <tt>outcomes</tt> is present, not null, and not an object; or one of its keys is not in <tt>performed_actions</tt>; or one of its values is not <tt>"ok"</tt>, <tt>"error"</tt>, <tt>"timeout"</tt> or <tt>"partial"</tt>,</li>
<li>(execution) it lists more than 256 performed actions,</li>
<li>(execution) a performed action, or the <tt>action</tt> of an approval that is an object, does not match <tt>^[a&nbhy;z][a&nbhy;z0&nbhy;9_.:&nbhy;]{0,63}$</tt>. An approval object with no <tt>action</tt> counts as not matching. (A name ending in a line feed never gets here: its body is not strict, <xref target="triage"/>.)</li>
</ul>
<t>If an execution with a problem has a contractor signature that verifies, it is a charge: the deviation <tt>nonconforming_record</tt> is added, and the record continues to <xref target="anchors"/>. Its acts are still judged. Any other record with a problem is rejected (disposition <tt>rejected</tt>). The computation is then repeated without the rejected records, until no new record is rejected, so no check reads a rejected record.</t>
<t>The types of <tt>approvals</tt>, <tt>delegated_to</tt>, <tt>nenrin_ref</tt> and <tt>contract_ref</tt> are checked in <xref target="triage"/>.</t>

</section>
</section>
<section anchor="anchors">
<name>Anchors</name>

<section anchor="anchor-what">
<name>What an Anchor Is</name>
<t>An anchor says where a record's body was committed to Bitcoin:</t>
<artwork type="ascii-art"><![CDATA[
"anchor": {"height": H, "block_hash": "<64 hex>", "proof": [op, ...]}
]]></artwork>
<t>The anchor is not signed. Anyone holding a record can change it. The checks below decide whether the claim holds against the verified view.</t>

</section>
<section anchor="anchor-height">
<name>Height</name>
<t>The height of a record is <tt>anchor.height</tt> when <tt>anchor</tt> is an object and <tt>height</tt> is an integer &gt;= 0. Otherwise the record has no height.</t>

</section>
<section anchor="anchor-order">
<name>Order of the Checks</name>
<t>For each record that passed <xref target="records"/>, apply <xref target="anchor-block"/>, <xref target="anchor-proof"/> and <xref target="batch-leg"/> in this order. The first failure decides what happens to the record. Every record that reaches this section is strictly signed by a party (<xref target="triage"/>).</t>

</section>
<section anchor="anchor-block">
<name>Height and Block</name>
<table>
<name>Height and block</name>
<thead><tr><th align="left">condition, in this order</th><th align="left">result</th></tr></thead>
<tbody>
<tr><td align="left">no height (<xref target="anchor-height"/>), or <tt>anchor.block_hash</tt> is not 64 lowercase hex</td><td align="left">underspecified reason <tt>anchor_incomplete</tt></td></tr>
<tr><td align="left">height &lt; <tt>lower_bound.height</tt></td><td align="left">underspecified reason <tt>anchor_below_lower_bound</tt>. The body names this contract, and the contract names the checkpoint's block hash, so no honest anchor can be below it</td></tr>
<tr><td align="left">height &gt; tip, or the view holds no header at that height</td><td align="left">underspecified reason <tt>anchor_beyond_observed_chain</tt></td></tr>
<tr><td align="left"><tt>anchor.block_hash</tt> != the view's hash at that height</td><td align="left">disposition <tt>orphaned</tt>: excluded, no reason added, but its height counts for finality (<xref target="status"/>)</td></tr>
</tbody></table>

</section>
<section anchor="anchor-proof">
<name>The Proof</name>
<t><tt>anchor.proof</tt> must be a non-empty list of at most 512 operations. Start with the 32 byte body digest (<xref target="digests"/>) as the current bytes, and apply each operation:</t>
<table>
<name>Proof operations</name>
<thead><tr><th align="left">op</th><th align="left">effect</th></tr></thead>
<tbody>
<tr><td align="left"><tt>{"op": "sha256"}</tt></td><td align="left">current = sha256(current)</td></tr>
<tr><td align="left"><tt>{"op": "hexlify"}</tt></td><td align="left">current = the ASCII bytes of the lowercase hex of current</td></tr>
<tr><td align="left"><tt>{"op": "append", "hex": X}</tt></td><td align="left">current = current + bytes(X)</td></tr>
<tr><td align="left"><tt>{"op": "prepend", "hex": X}</tt></td><td align="left">current = bytes(X) + current</td></tr>
</tbody></table>
<t><tt>X</tt> is a string of pairs of lowercase hex digits (the empty string is allowed) of at most 4096 bytes, and bytes(X) is the byte string that X encodes. (An operand with anything else, a line feed included, never gets here: the anchor is not strict, <xref target="triage"/>.) Any other op, a missing or malformed operand, a non-object entry, or current bytes longer than 65536 at any step, fails the proof. The proof holds if the final bytes equal the merkle root of the header at the record's height (<xref target="view-verify"/>). If it fails: underspecified reason <tt>anchor_proof_invalid</tt>.</t>
<t>The operation set resembles a subset of the operations used by OpenTimestamps <xref target="OPENTIMESTAMPS"/>; only the operations above are defined here.</t>

</section>
<section anchor="batch-leg">
<name>The Batch Leg Rule</name>
<t>A ledger lists records by their hex sha inside a batch, and stamps the batch. A proof can pass through such a batch with <tt>hexlify</tt>. A hex digest that merely appears somewhere in stamped bytes is not a listing. So:</t>
<ol>
<li>If no op in the proof is <tt>hexlify</tt>, the rule accepts.</li>
<li>If any <tt>hexlify</tt> is not the first op, or there is more than one, refuse (<tt>hexlify_not_leading</tt>).</li>
<li>Rebuild the batch: walk the ops after the first one, up to the first <tt>sha256</tt>. Each must be <tt>append</tt> or <tt>prepend</tt>, else refuse (<tt>batch_leg_malformed</tt>). If there is no <tt>sha256</tt>, refuse (<tt>batch_leg_malformed</tt>). The batch is (all prepend operands, the later one in front) + the ASCII lowercase hex of the body digest + (all append operands, in order).</li>
<li>The batch bytes must be UTF-8 text that parses as strict JSON (<xref target="reading-json"/>) into an object whose <tt>schema</tt> is one of <tt>nenrin&nbhy;agreement&nbhy;batch&nbhy;v1</tt> (typed), <tt>nenrin&nbhy;witness&nbhy;batch&nbhy;v1</tt>, <tt>nenrin&nbhy;trace&nbhy;pin&nbhy;batch&nbhy;v0</tt>. Else refuse (<tt>batch_not_json</tt> or <tt>batch_schema_unknown</tt>).</li>
<li><tt>records</tt> is a list of objects (else <tt>batch_schema_unknown</tt>). If <tt>count</tt> is present it equals the length of <tt>records</tt> (else <tt>batch_count_mismatch</tt>).</li>
<li>Exactly one <tt>records[i]</tt> has <tt>sha</tt> equal to the hex digest. None: <tt>record_not_listed_in_batch</tt>. More: <tt>record_listed_twice</tt>.</li>
<li>For a typed batch: the record's schema maps to a kind (<tt>a2a&nbhy;execution&nbhy;v0</tt> to <tt>execution</tt>; revocations and acknowledgements have no kind, so they are refused with <tt>record_kind_unknown</tt>, WRITTEN BEHAVIOUR). <tt>records[i].kind</tt> equals that kind (else <tt>record_kind_mismatch</tt>). If <tt>records[i].schema</tt> is present it equals the record's schema (else <tt>record_schema_mismatch</tt>).</li>
<li>The string value of <tt>records[i].sha</tt> must be written in the raw text as the 64 hex characters themselves, with no escapes (else refuse, code <tt>internal</tt>), and its first character must sit at byte offset equal to the total length of the prepend operands (else refuse, <tt>batch_leg_splice_not_at_listing</tt>).</li>
</ol>
<t>If the rule refuses: underspecified reason <tt>anchor_batch_leg_refused</tt>. The refusal code is informative detail.</t>
<t>If all of <xref target="anchor-block"/> to <xref target="batch-leg"/> pass, the record is accepted (disposition <tt>accepted</tt>).</t>

</section>
</section>
<section anchor="event-set">
<name>The Event Set and Finality</name>

<section anchor="event-order">
<name>Order</name>
<t>The event set is the accepted records sorted by (height, record_sha256 as a lowercase hex string). Arrival order plays no part.</t>

</section>
<section anchor="event-kinds">
<name>Kinds</name>
<t>Each event has a kind: <tt>execution</tt>, <tt>revocation</tt> or <tt>revocation_ack</tt>, by schema.</t>

</section>
<section anchor="same-block">
<name>Same Block</name>
<t>Two records in the same block are not ordered by their bytes for any rule that matters. <xref target="grant"/> says how same-block cases are decided. The order of <xref target="event-order"/> only fixes the listing and the order in which single use approvals are consumed (<xref target="approvals"/>).</t>

</section>
<section anchor="horizon">
<name>Horizon</name>
<t>With tip T and <tt>grant.finality.depth</tt> k, the finality horizon is <tt>T &nbhy; k + 1</tt>.</t>

</section>
<section anchor="status">
<name>Status</name>
<ul>
<li>If the verdict is <tt>underspecified</tt>: <tt>undetermined</tt>.</li>
<li>Otherwise <tt>final</tt> if every accepted record's height and every orphaned record's height is at or below the horizon; else <tt>provisional</tt>.</li>
</ul>
<t>With no accepted and no orphaned record, the status is <tt>final</tt>. Foreign, rejected, ignored and set aside records do not affect status.</t>

</section>
</section>
<section anchor="output">
<name>Output</name>

<section anchor="core-fields">
<name>Core Fields</name>
<t>A second implementation <bcp14>MUST</bcp14> reproduce these exactly. They are what the vectors' expected.json files hold.</t>
<table>
<name>Core fields</name>
<thead><tr><th align="left">field</th><th align="left">value</th></tr></thead>
<tbody>
<tr><td align="left"><tt>contract_sha256</tt></td><td align="left"><xref target="digests"/>, always computed, even for a contract the door refuses</td></tr>
<tr><td align="left"><tt>verdict</tt></td><td align="left"><tt>within_grant</tt>, <tt>deviation</tt>, <tt>nothing_to_settle</tt> or <tt>underspecified</tt> (<xref target="verdict"/>)</td></tr>
<tr><td align="left"><tt>status</tt></td><td align="left"><tt>final</tt>, <tt>provisional</tt> or <tt>undetermined</tt> (<xref target="status"/>)</td></tr>
<tr><td align="left"><tt>bond_outcome</tt></td><td align="left"><xref target="bond-outcome"/></td></tr>
<tr><td align="left"><tt>deviation_codes</tt></td><td align="left">the sorted set of deviation codes (<xref target="codes"/>). Empty when the verdict is not <tt>deviation</tt></td></tr>
<tr><td align="left"><tt>underspecified_reasons</tt></td><td align="left">the sorted set of underspecified reasons (<xref target="codes"/>). Empty unless the verdict is <tt>underspecified</tt></td></tr>
<tr><td align="left"><tt>event_set</tt></td><td align="left">the list of <xref target="event-order"/>, each item <tt>{"kind", "sha256", "height"}</tt> with sha256 the record_sha256. Empty when the walk did not run. A reason from <xref target="strict-terms"/>, rule 9 of <xref target="view-verify"/>, <xref target="triage"/>, <xref target="anchor-block"/> (below the lower bound) or <xref target="nenrin"/> (a cited walk) does not empty it</td></tr>
<tr><td align="left"><tt>dispositions</tt></td><td align="left">an object mapping record_sha256 to one code, for every record the computation classified (<xref target="dispositions"/>)</td></tr>
</tbody></table>
<t><tt>deviation_codes</tt> and <tt>underspecified_reasons</tt> are sets. The reference may list a code more than once (one per action); that multiplicity is informative.</t>

</section>
<section anchor="dispositions">
<name>Dispositions</name>
<table>
<name>Dispositions</name>
<thead><tr><th align="left">code</th><th align="left">meaning</th></tr></thead>
<tbody>
<tr><td align="left"><tt>foreign</tt>, <tt>inconsistent</tt>, <tt>unbound</tt></td><td align="left"><xref target="binding"/></td></tr>
<tr><td align="left"><tt>record_not_strict</tt>, <tt>signature_not_strict</tt>, <tt>anchor_not_strict</tt>, <tt>revocation_not_provided_for</tt></td><td align="left"><xref target="triage"/>, set aside, or (for <tt>record_not_strict</tt> and <tt>anchor_not_strict</tt>) failing closed with the same reason added to the settlement</td></tr>
<tr><td align="left"><tt>duplicate_dropped</tt></td><td align="left"><xref target="collapse"/></td></tr>
<tr><td align="left"><tt>rejected</tt></td><td align="left"><xref target="triage"/> or <xref target="conformance"/></td></tr>
<tr><td align="left"><tt>ignored</tt></td><td align="left"><xref target="authentication"/>, a revocation whose <tt>revoked_by</tt> is not <tt>"principal"</tt></td></tr>
<tr><td align="left"><tt>anchor_incomplete</tt>, <tt>anchor_beyond_observed_chain</tt>, <tt>anchor_proof_invalid</tt>, <tt>anchor_batch_leg_refused</tt></td><td align="left"><xref target="anchor-block"/> to <xref target="batch-leg"/>, with the same reason added to the settlement</td></tr>
<tr><td align="left"><tt>anchor_below_lower_bound</tt></td><td align="left"><xref target="anchor-block"/>, with the same reason added</td></tr>
<tr><td align="left"><tt>orphaned</tt></td><td align="left"><xref target="anchor-block"/></td></tr>
<tr><td align="left"><tt>accepted</tt></td><td align="left">in the event set</td></tr>
</tbody></table>
<t>A bound record that the computation never examined (because <xref target="contract"/>, <xref target="view"/> or <xref target="size-limit"/> failed) has no disposition. A record that is not ours (<xref target="binding"/>, dropped silently) has no disposition. A record set aside because it cannot be digested has no record_sha256 and so no disposition; it is counted in the informative <tt>v1_16.refused</tt>. Every record has at most one disposition.</t>

</section>
<section anchor="bond-outcome">
<name>Bond Outcome</name>
<t>If <tt>contract.bond</tt> is absent or null: <tt>n/a</tt>. A bond of any other form than an object with a positive integer <tt>amount</tt> makes the settlement underspecified (<xref target="strict-terms"/>) and the outcome is then <tt>undetermined</tt> when the value is one the lower layers read as a bond (an object with a truthy <tt>amount</tt>), else <tt>n/a</tt>.</t>
<t>For a well formed bond: <tt>undetermined</tt> if the verdict is <tt>underspecified</tt>; else <tt>pending_finality</tt> if the status is <tt>provisional</tt>; else <tt>held</tt> for <tt>within_grant</tt> and <tt>nothing_to_settle</tt>, and <tt>forfeited</tt> for <tt>deviation</tt>.</t>

</section>
<section anchor="informative-fields">
<name>Informative Fields</name>
<t>Everything else the reference writes is informative: <tt>schema</tt>, <tt>settled_under</tt>, <tt>v1_16</tt>, <tt>signed_body_collapse</tt>, <tt>contract_id</tt>, <tt>binding_mode</tt>, <tt>bound_by_label_only</tt>, <tt>ordering_rule</tt>, <tt>approval_rule</tt>, <tt>anchor_rule</tt>, <tt>view_rules</tt>, <tt>chain_tip</tt>, <tt>finality_horizon</tt>, <tt>pinned_blocks</tt>, <tt>revocations</tt>, <tt>approvals</tt>, <tt>binding</tt>, <tt>orphaned</tt>, <tt>predates_contract</tt>, <tt>ignored</tt>, <tt>rejected</tt>, <tt>duplicate_anchorings</tt>, <tt>establishes</tt>, <tt>does_not_establish</tt>, <tt>spine_gate</tt>, <tt>convergence_gate</tt>, <tt>approval_gate</tt>, <tt>signatures</tt>, the full <tt>underspecified</tt> and <tt>deviations</tt> objects (heights, <tt>why</tt> texts, details), and their order. The informative fields are useful when comparing implementations. They are not part of conformance.</t>

</section>
</section>
<section anchor="grant">
<name>Grant Evaluation</name>
<t>The walk runs over the event set (<xref target="event-order"/>) only. Let <tt>g = contract.grant</tt>.</t>
<section anchor="revocation">
<name>Revocation</name>
<t>For each accepted revocation at height h, its effective height E is:</t>
<ul>
<li><tt>effective_at</tt> <tt>"anchor"</tt>: E = h.</li>
<li><tt>effective_at</tt> <tt>"delivery_ack"</tt>: E = the smallest of h + <tt>ack_window</tt> and the heights of every accepted acknowledgement whose <tt>revocation_sha256</tt> names this revocation.</li>
</ul>
<t>An acknowledgement names a revocation if its <tt>revocation_sha256</tt> equals the lowercase hex body digest of the revocation, or the record_sha256 of any bound copy of that revocation (any anchoring, counted before <xref target="collapse"/> drops copies). An acknowledgement anchored before its revocation makes E earlier than h (WRITTEN BEHAVIOUR, see item N5 of <xref target="MUSUBI-NOTES"/>).</t>
<t>Sort the revocations by (E, record_sha256). An execution at height h is revoked if some revocation has E &lt;= h. Authority ends at block E inclusive: an act in the same block as an anchor-mode revocation is revoked. For a revoked execution, every string in <tt>performed_actions</tt> gives the deviation <tt>revoked</tt>, and nothing else in that record is judged (no expiry, prohibited, conditional, unauthorized or delegation check, and no approval nonce is consumed).</t>
<t>If the grant has no <tt>revocation</tt> object, a revocation never gets here: it is set aside in <xref target="triage"/> (<tt>revocation_not_provided_for</tt>).</t>

</section>
<section anchor="expiry">
<name>Expiry</name>
<t>If <tt>g.expiry_height</tt> is present and not null, every string action of an execution with height h &gt; expiry_height gives <tt>after_expiry</tt>. This does not stop the other checks for that action: an expired prohibited action gives both <tt>after_expiry</tt> and <tt>prohibited</tt>. An execution at exactly expiry_height is not expired.</t>

</section>
<section anchor="actions">
<name>Actions and Delegation</name>
<t>For each accepted, unrevoked execution, for each string <tt>a</tt> in <tt>performed_actions</tt>, in order, after <xref target="expiry"/>:</t>
<ol>
<li>If <tt>a</tt> is in <tt>g.prohibited_actions</tt>: deviation <tt>prohibited</tt>. Next action.</li>
<li>Else if <tt>a</tt> is the <tt>action</tt> of some <tt>g.conditional</tt> entry: apply <xref target="approvals"/>. Next action. (A conditional action does not need to be in <tt>authorized_actions</tt>.)</li>
<li>Else if <tt>a</tt> is not in <tt>g.authorized_actions</tt>: deviation <tt>unauthorized</tt>.</li>
</ol>
<t>Every entry of <tt>performed_actions</tt> and <tt>delegated_to</tt> is a string here (<xref target="triage"/>). Comparison is exact string equality. There is no case folding or Unicode normalization.</t>
<t>Then, for each entry <tt>d</tt> of <tt>delegated_to</tt> not in <tt>g.delegation.allowed</tt> (empty when absent): deviation <tt>delegation</tt>. An outcome (<tt>outcomes</tt>) never excuses an act. An attempt that errored is judged like one that succeeded.</t>

</section>
<section anchor="approvals">
<name>Conditional Actions and Approvals</name>
<t>Every approval carried by an accepted execution (revoked or not) is classified. With <tt>pk</tt> the principal's key and <tt>csha</tt> this contract's contract_sha256:</t>
<ol>
<li>Not an object, or no principal key: <tt>forged</tt> (<xref target="forged"/>).</li>
<li>If <tt>valid_until_height</tt> is an integer &gt;= 0, <tt>nonce</tt> is a string of 32 lowercase hex characters (a nonce with a line feed never gets here, <xref target="triage"/>), <tt>single_use</tt> is a boolean, and <tt>contract_sha256</tt> is 64 lowercase hex: compute the v2 approval bytes shown after this list. If <tt>sig_b64</tt> verifies over them with <tt>pk</tt>: <tt>counted</tt> when its contract_sha256 equals csha, else <tt>other_terms</tt>.</li>
<li><t>Otherwise, if <tt>sig_b64</tt> verifies with <tt>pk</tt> over either older form, it is <tt>label_bound</tt>:</t>
<ul>
<li>the v1 approval bytes, with contract_id and payload_digest from the contract, only when the field checks of step 2 other than contract_sha256 hold, or</li>
<li>the v0 approval bytes.</li>
</ul></li>
<li>Otherwise <tt>forged</tt>.</li>
</ol>
<t>The three forms of approval bytes are:</t>
<figure><name>Approval signing bytes</name><artwork type="ascii-art"><![CDATA[
v2: "a2a-approval-v2\n" + canonical({
      "contract_sha256": <its contract_sha256>,
      "action": <its action>,
      "valid_until_height": ..,
      "nonce": ..,
      "single_use": ..})

v1: "a2a-approval-v1\n" + canonical({
      "contract_id", "payload_digest", "action",
      "valid_until_height", "nonce", "single_use"})

v0: "a2a-approval-v0\n" + canonical({
      "contract_id", "payload_digest", "action"})
]]></artwork></figure>
<t>A missing field is canonicalized as null. The approval's <tt>by</tt> field is not read. <tt>label_bound</tt> and <tt>other_terms</tt> approvals are listed (informative) and never count. They are not deviations.</t>
<t>A conditional action <tt>a</tt> in an execution at height h with record sha s is approved if some counted approval, taken in event set order (records by <xref target="event-order"/>, approvals in list order within a record), satisfies all of:</t>
<ul>
<li>its <tt>action</tt> equals <tt>a</tt>,</li>
<li>it is carried by the same record s, or by a record at a height strictly below h (a record in the same block does not count),</li>
<li>h &lt;= its <tt>valid_until_height</tt>,</li>
<li>if its <tt>single_use</tt> is true, its <tt>nonce</tt> has not been consumed yet.</li>
</ul>
<t>The first approval that satisfies all four is used. If it is single use, its nonce is consumed. The set of consumed nonces is shared across all actions and all executions (see item N5 of <xref target="MUSUBI-NOTES"/>). If no approval satisfies all four: deviation <tt>conditional</tt>. The value of <tt>requires</tt> in the conditional entry is not read: every conditional action needs a counted approval.</t>

</section>
<section anchor="forged">
<name>Forged Approvals</name>
<t>Every approval classified <tt>forged</tt> adds the deviation <tt>forged_approval</tt>, whatever its action, whether or not the action was needed.</t>

</section>
</section>
<section anchor="nenrin">
<name>NENRIN Checks</name>

<section anchor="nenrin-cross">
<name>Cross Check</name>
<t>Only when <tt>nenrin_records</tt> is a non-empty list. A walk that is not strict (first paragraph of <xref target="triage"/>) is left out. Index every other object in it by its record_sha256 (<xref target="digests"/>). For each execution kept by <xref target="triage"/> and not rejected by <xref target="conformance"/>, left after <xref target="collapse"/> (once per record_sha256), look up the walk whose record_sha256 equals the execution's <tt>nenrin_ref</tt>. If found, and the walk's <tt>context</tt> is an object whose <tt>contract_sha256</tt> is present, not null, and not equal to csha: deviation <tt>evidence_names_other_contract</tt>. If an execution's <tt>nenrin_ref</tt> names a walk that was left out for not being strict: underspecified reason <tt>walk_not_strict</tt>. The contractor chose what to cite, and leaving the walk out silently could hide a deviation.</t>
<t>Records that were rejected or set aside are never checked here (item N2 of <xref target="MUSUBI-NOTES"/>).</t>

</section>
<section anchor="nenrin-required">
<name>Required Evidence</name>
<t>When <tt>requirements.evidence</tt> is <tt>"nenrin_required"</tt>, each accepted execution whose <tt>nenrin_ref</tt> is not 64 lowercase hex gives the deviation <tt>evidence_missing</tt>. This is applied after <xref target="verdict"/> found <tt>within_grant</tt> or <tt>deviation</tt>.</t>

</section>
</section>
<section anchor="verdict">
<name>Verdict</name>
<ul>
<li><tt>underspecified</tt> if any underspecified reason was found (<xref target="contract"/>, <xref target="view"/>, <xref target="triage"/>, <xref target="size-limit"/>, <xref target="anchors"/>, <xref target="nenrin"/>). Then <tt>deviations</tt> is empty and status is <tt>undetermined</tt>.</li>
<li>Else <tt>deviation</tt> if any deviation was found (<xref target="conformance"/>, <xref target="grant"/>, <xref target="nenrin"/>).</li>
<li>Else <tt>nothing_to_settle</tt> if the event set is empty: no record was read, so nothing was found within the grant or outside it. Status is as <xref target="status"/> gives it (<tt>final</tt> with no orphaned record).</li>
<li>Else <tt>within_grant</tt>.</li>
</ul>
<t><tt>within_grant</tt> covers only the accepted records. One strictly signed record whose anchor fails <xref target="anchor-block"/> (first, second or third row), <xref target="anchor-proof"/> or <xref target="batch-leg"/> makes the whole settlement <tt>underspecified</tt>. A record that is not strictly signed never does.</t>

</section>
<section anchor="written-behaviour">
<name>Written Behaviour and Changes from Earlier Settle Versions</name>

<section anchor="wb-list">
<name>Written Behaviour</name>
<t>These are what the reference still does. They are normative for core v0 because the vectors pin them, or would.</t>
<table>
<name>Written behaviour</name>
<thead><tr><th align="left">item</th><th align="left">vector</th></tr></thead>
<tbody>
<tr><td align="left">An extra bad signature from a party refuses the contract even when that party also signed correctly</td><td align="left">none</td></tr>
<tr><td align="left">Revocations and acknowledgements cannot pass a typed batch leg (no kind)</td><td align="left">none</td></tr>
<tr><td align="left">An acknowledgement anchored before its revocation ends authority at the acknowledgement's height</td><td align="left">none</td></tr>
<tr><td align="left">An orphaned record is excluded without making the settlement underspecified, yet its claimed height still counts for status</td><td align="left"><tt>real_p31_anchor_names_other_height</tt></td></tr>
<tr><td align="left">A header ending in a line feed passes rules 1 to 8 of <xref target="view-verify"/> and is refused only by rule 9 (<tt>view_not_strict</tt>); one in upper case is refused by both</td><td align="left"><tt>synth_view_header_trailing_newline</tt></td></tr>
<tr><td align="left">A party-signed record that names this contract_sha256 with another contract_id or payload_digest is inconsistent (<xref target="binding"/>) and is never triaged, so a deviation it shows is not read</td><td align="left">none</td></tr>
</tbody></table>

</section>
<section anchor="changes">
<name>Changes in Settle v1.16</name>
<t>Each item below was written behaviour of settle v1.10 to v1.15; <xref target="MUSUBI-NOTES"/> has the details under the item numbers given.</t>
<table>
<name>Changes in settle v1.16</name>
<thead><tr><th align="left">item</th><th align="left">before</th><th align="left">now</th></tr></thead>
<tbody>
<tr><td align="left">N2</td><td align="left">The NENRIN cross check read every bound execution, also rejected and unsigned ones: anyone could add a charge and forfeit a bond</td><td align="left">only records strictly signed and not rejected are read by any check</td></tr>
<tr><td align="left">N1</td><td align="left">A trailing line feed passed in block_hash, proof operands, headers, action names and approval nonces</td><td align="left">strict forms (<xref target="triage"/>, rule 9 of <xref target="view-verify"/>)</td></tr>
<tr><td align="left">N3, N6</td><td align="left"><tt>delegated_to</tt> and <tt>approvals</tt> were not type checked; an object in <tt>delegated_to</tt> stopped the reference</td><td align="left"><xref target="triage"/></td></tr>
<tr><td align="left">N4</td><td align="left">Floats and unsafe integers in records, views and walks were accepted</td><td align="left"><xref target="triage"/>, rule 9 of <xref target="view-verify"/>, <xref target="nenrin-cross"/></td></tr>
<tr><td align="left">N6</td><td align="left">A revocation against a grant with no revocation block stopped the reference</td><td align="left">set aside</td></tr>
<tr><td align="left">N8</td><td align="left">The bond test used truthiness, so <tt>[]</tt> was no bond in Python and a bond in JavaScript</td><td align="left"><tt>bond_malformed</tt></td></tr>
<tr><td align="left">N9</td><td align="left">Signatures were checked by OpenSSL alone</td><td align="left">strict signatures (<xref target="ed25519"/>)</td></tr>
<tr><td align="left">N10</td><td align="left">A copy with a junk signatures entry was a second body that blocked the verdict (fixed in v1.15)</td><td align="left">copies of one signed body collapse (<xref target="collapse"/>)</td></tr>
<tr><td align="left">N11</td><td align="left">An anchor below the checkpoint was dropped without a word; <tt>parent_contract</tt> and <tt>requirements.evidence</tt> were never read; an empty event set was <tt>within_grant</tt></td><td align="left"><tt>anchor_below_lower_bound</tt>; <xref target="strict-terms"/>; <xref target="nenrin-required"/>; <tt>nothing_to_settle</tt></td></tr>
</tbody></table>
<t>The vectors that pin each change are:</t>
<table>
<name>Vectors for the changes in settle v1.16</name>
<thead><tr><th align="left">item</th><th align="left">vectors</th></tr></thead>
<tbody>
<tr><td align="left">N2</td><td align="left"><tt>synth_nenrin_check_reads_rejected_record</tt>, <tt>synth_unsigned_copies_anchored_first</tt></td></tr>
<tr><td align="left">N1</td><td align="left"><tt>real_p31_proof_operand_trailing_newline</tt>, <tt>real_p31_proof_operand_trailing_newline_beside_good</tt>, <tt>real_p31_block_hash_trailing_newline</tt>, <tt>synth_action_name_trailing_newline</tt>, <tt>synth_approval_nonce_trailing_newline</tt>, <tt>synth_view_header_trailing_newline</tt></td></tr>
<tr><td align="left">N3, N6</td><td align="left"><tt>synth_delegated_to_object</tt></td></tr>
<tr><td align="left">N4</td><td align="left"><tt>synth_float_in_signed_body</tt>, <tt>synth_unsafe_integer_in_signed_body</tt>, <tt>synth_unsigned_float_beside_good</tt>, <tt>synth_cited_walk_not_strict</tt></td></tr>
<tr><td align="left">N6</td><td align="left"><tt>synth_revocation_irrevocable_grant</tt></td></tr>
<tr><td align="left">N8</td><td align="left"><tt>synth_bond_empty_list</tt>, <tt>synth_bond_amount_string</tt></td></tr>
<tr><td align="left">N9</td><td align="left"><tt>synth_signature_s_plus_l</tt>, <tt>synth_strict_signature_beside_malleated</tt>, <tt>real_p31_contract_bad_principal_signature</tt></td></tr>
<tr><td align="left">N10</td><td align="left"><tt>real_p31_copy_with_junk_signature_entry</tt></td></tr>
<tr><td align="left">N11</td><td align="left"><tt>real_p31_anchor_below_checkpoint</tt>, <tt>synth_parent_not_supplied</tt>, <tt>synth_parent_supplied_narrows</tt>, <tt>synth_parent_widened</tt>, <tt>synth_nenrin_required_without_ref</tt>, <tt>synth_nothing_to_settle</tt></td></tr>
</tbody></table>

</section>
</section>
<section anchor="vectors">
<name>Test Vectors</name>

<section anchor="vectors-contents">
<name>Contents</name>
<t>The vectors are published beside the source text of this document at commit 4100d52a <xref target="MUSUBI-VECTORS"/>, in the folder settle-core-v0/vectors/ under <eref target="https://github.com/ogasurfproject-jpg/horizon-shield/tree/4100d52a/workers/hs-ledger/nenrin/musubi-v0/settle-core-v0"/>. They are not reproduced here.</t>
<t>There are 76 vectors: 22 real and 54 synthetic. Their expected verdicts are <tt>within_grant</tt> for 23, <tt>deviation</tt> for 19, <tt>nothing_to_settle</tt> for 8 and <tt>underspecified</tt> for 26.</t>
<t>The folder holds one subfolder per vector:</t>
<ul>
<li><tt>contract.json</tt>, <tt>view.json</tt>, <tt>events/eNN.json</tt> (the events, in any order), <tt>nenrin/nNN.json</tt> when the vector supplies walks, <tt>parent.json</tt> when it supplies a parent contract,</li>
<li><tt>expected.json</tt>: the core fields (<xref target="core-fields"/>).</li>
</ul>
<t>The index vectors/vectors.json lists, for each vector, its id, its family (real or synthetic), the section of the source text it tests, a description, the expected verdict, status and code sets, and the sha256 of each of its files. It also lists the four synthetic public keys.</t>
<t>Real vectors use the real records, contracts and Bitcoin headers of two settled engagements, with one change each (the record bodies cannot change without breaking the real Bitcoin anchors). <tt>real_p31_baseline</tt> is the first MUSUBI contract settled with no party from the project that publishes the reference (agent-passport.org and kuangmi-bit.github.io, Bitcoin block 970480), with its 359 header view.</t>
<t>Synthetic vectors use keys named synthetic-principal, synthetic-contractor, synthetic-witness and synthetic-stranger, derived from fixed seeds, and a synthetic header chain at regtest difficulty (<tt>max_target_bits</tt> <tt>207fffff</tt>, checkpoint height 800001). The public keys are:</t>
<table>
<name>Synthetic keys</name>
<thead><tr><th align="left">name</th><th align="left">public_key_ed25519_b64</th></tr></thead>
<tbody>
<tr><td align="left">synthetic-principal</td><td align="left"><tt>rrXBDf5mF249t6wdmMvKtkcBXZmVVfcfYFBBjIpSttE=</tt></td></tr>
<tr><td align="left">synthetic-contractor</td><td align="left"><tt>hl3xmxz86HFYXTczn/5HZw4Jkb3i0nL7iig/2GXZrcs=</tt></td></tr>
<tr><td align="left">synthetic-witness</td><td align="left"><tt>gMKIYPPIjG6r9mt8ybr3dIGGm6LYxkngSym9ltvHNtY=</tt></td></tr>
<tr><td align="left">synthetic-stranger</td><td align="left"><tt>YmzNu/v6K9wUOtcmnssHABVLBDuLBqMcZnM0NL+32rU=</tt></td></tr>
</tbody></table>
<t>gen_vectors.py regenerates every vector from the two real inputs and the reference; it is deterministic. run_reference.py runs the reference over every vector and checks every file hash and every core field.</t>

</section>
<section anchor="projection">
<name>The Core-Field Projection</name>
<t>expected.json holds exactly the eight core fields of <xref target="core-fields"/> and nothing else. The reference's full settlement object is projected onto them as follows:</t>
<ul>
<li><tt>contract_sha256</tt>, <tt>verdict</tt>, <tt>status</tt> and <tt>bond_outcome</tt> are copied.</li>
<li><tt>deviation_codes</tt> and <tt>underspecified_reasons</tt> are the sorted sets of the codes in the reference's <tt>deviations</tt> and <tt>underspecified</tt> lists. Repetitions are removed.</li>
<li><tt>event_set</tt> keeps, for each accepted record in the order of <xref target="event-order"/>, only <tt>kind</tt>, <tt>sha256</tt> and <tt>height</tt>.</li>
<li><tt>dispositions</tt> is one object from record_sha256 to one disposition code (<xref target="dispositions"/>), with keys sorted. A record that would receive two different codes is an error of the projection.</li>
</ul>
<t>An implementation conforms on a vector when its eight core fields are equal to expected.json as JSON values. The informative fields (<xref target="informative-fields"/>) are not compared.</t>

</section>
<section anchor="disagreement">
<name>Reporting a Disagreement</name>
<t>A disagreement is valuable. It means either the text, the reference or the implementation is wrong, and only a comparison finds out which.</t>
<ol>
<li>Run the implementation over the vectors. For each vector, compare its core fields (<xref target="core-fields"/>) with <tt>expected.json</tt>.</li>
<li>Run <tt>python3 run_reference.py</tt> from the folder holding the source text, to confirm the reference still gives the expected values on the same machine.</li>
<li>For each vector with a disagreement, write down: the vector id; the core field; the expected value and the implementation's; the section of this document followed; and, if possible, the step where the computation first diverged (for example "conformance: the name was treated as nonconforming").</li>
<li>Say whether the vector is listed in <xref target="written-behaviour"/>. If it is, say whether the behaviour should change.</li>
<li>For a disagreement on an input that is not a vector, attach the input files (contract, events, view, walks) so the reference can be run on them.</li>
<li>Open an issue on the repository that publishes the source text (at the time of writing github.com/ogasurfproject-jpg/horizon-shield) titled <tt>settle core v0 disagreement: &lt;vector id&gt;</tt>, with the above.</li>
</ol>
<t>An implementer should not change an implementation to match a vector believed to be wrong without saying so. A silent match hides a defect. A reported disagreement is resolved by changing this text, the reference, or the vector, and the change is recorded with a new version of this document.</t>

</section>
</section>
<section anchor="impl-status">
<name>Implementation Status</name>
<t>Note to the RFC Editor: please remove this section before publication.</t>
<t>This section records the status of known implementations of the protocol defined by this specification at the time of posting of this Internet-Draft, and is based on a proposal described in <xref target="RFC7942"/>. The description of implementations in this section is intended to assist the IETF in its decision processes in progressing drafts to RFCs. Please note that the listing of any individual implementation here does not imply endorsement by the IETF. Furthermore, no effort has been spent to verify the information presented here that was supplied by IETF contributors. This is not intended as, and must not be construed to be, a catalog of available implementations or their features. Readers are advised to note that other implementations may exist.</t>
<t>According to <xref target="RFC7942"/>, "this will allow reviewers and working groups to assign due consideration to documents that have the benefit of running code, which may serve as evidence of valuable experimentation and feedback that have made the implemented protocols more mature. It is up to the individual working groups to use this information as they see fit".</t>
<section anchor="impl-ref">
<name>Reference Implementation</name>
<dl newline="false">
<dt>Organization:</dt><dd>The HORIZONs Co., Ltd.</dd>
<dt>Implementation:</dt><dd>settle_v1_16.py (output schema a2a-settlement-v1.16) and the modules it imports, at commit 4100d52a <xref target="MUSUBI-REF"/>. It is called as a library, <tt>settle_v1_16.settle_v1_16(contract, events, view, parent=..., nenrin_records=...)</tt>. Its command line (<tt>&nbhy;&nbhy;settle</tt>, <tt>&nbhy;&nbhy;event</tt>, <tt>&nbhy;&nbhy;view</tt>, <tt>&nbhy;&nbhy;nenrin</tt>, <tt>&nbhy;&nbhy;parent</tt>) first checks each view's strict form and runs fork choice, and for a view that does not pass prints why and writes no settlement. The vectors use the library.</dd>
<dt>Description:</dt><dd>The implementation from which this document was written. It covers all of settle core v0 and the gates outside its scope (<xref target="scope"/>).</dd>
<dt>Maturity:</dt><dd>Reference. Its behaviour defines the expected values of the vectors.</dd>
<dt>Coverage:</dt><dd>All of settle core v0. The canonical form (<xref target="canonical"/>) is also implemented in JavaScript (canonical_v0.mjs), which covers only that section.</dd>
<dt>Licensing:</dt><dd>MIT.</dd>
<dt>Implementation experience:</dt><dd>run_reference.py reports "76/76 vectors agree with the reference" with Python 3.13.16 and the Python package cryptography 50.0.1.</dd>
<dt>Contact:</dt><dd>Toshikatsu Oga, thehorizon.nnovation@icloud.com</dd>
<dt>Last updated:</dt><dd>2026-10-17</dd>
</dl>
<t>The reference, as run for the vectors, consists of these files (first 16 hex digits of each file's sha256):</t>
<table>
<name>Reference files</name>
<thead><tr><th align="left">file</th><th align="left">sha256 prefix</th></tr></thead>
<tbody>
<tr><td align="left">settle_v1.py</td><td align="left"><tt>0e51350331c8931c</tt></td></tr>
<tr><td align="left">settle_v1_1.py</td><td align="left"><tt>a2391a5db199bcda</tt></td></tr>
<tr><td align="left">settle_v1_2.py</td><td align="left"><tt>6c674fd54a1a5c89</tt></td></tr>
<tr><td align="left">settle_v1_3.py</td><td align="left"><tt>17119bbc7802647f</tt></td></tr>
<tr><td align="left">settle_v1_4.py</td><td align="left"><tt>ef3779d05fc98e40</tt></td></tr>
<tr><td align="left">settle_v1_5.py</td><td align="left"><tt>f9b313566713cdc4</tt></td></tr>
<tr><td align="left">settle_v1_6.py</td><td align="left"><tt>6752a748ed7b6e3b</tt></td></tr>
<tr><td align="left">settle_v1_7.py</td><td align="left"><tt>878a3a3697775d3a</tt></td></tr>
<tr><td align="left">settle_v1_8.py</td><td align="left"><tt>fe61f67c1593c776</tt></td></tr>
<tr><td align="left">settle_v1_9.py</td><td align="left"><tt>7a84302be1ec38a1</tt></td></tr>
<tr><td align="left">settle_v1_10.py</td><td align="left"><tt>34beeebaa1397059</tt></td></tr>
<tr><td align="left">settle_v1_11.py</td><td align="left"><tt>fb03687cbacd2713</tt></td></tr>
<tr><td align="left">settle_v1_12.py</td><td align="left"><tt>40a8fbb82a8e7680</tt></td></tr>
<tr><td align="left">settle_v1_13.py</td><td align="left"><tt>eb02b3a6544b1bf1</tt></td></tr>
<tr><td align="left">settle_v1_14.py</td><td align="left"><tt>7d0704fa060adafd</tt></td></tr>
<tr><td align="left">settle_v1_15.py</td><td align="left"><tt>a2be5de8ba60656e</tt></td></tr>
<tr><td align="left">settle_v1_16.py</td><td align="left"><tt>ec332ecb387e9b56</tt></td></tr>
<tr><td align="left">admission_verify_v0.py</td><td align="left"><tt>aa889e542ff40e25</tt></td></tr>
<tr><td align="left">agreement_verify.py</td><td align="left"><tt>72990326ac4a0a65</tt></td></tr>
<tr><td align="left">anchor_compose.py</td><td align="left"><tt>a661f673c05dbe6e</tt></td></tr>
<tr><td align="left">approval_v3.py</td><td align="left"><tt>e8dde985dbe6fbf4</tt></td></tr>
<tr><td align="left">clause_eval_v0.py</td><td align="left"><tt>fee48c3a66c28fe1</tt></td></tr>
<tr><td align="left">contract_v0.py</td><td align="left"><tt>211a568783705e11</tt></td></tr>
<tr><td align="left">convergence_v0.py</td><td align="left"><tt>65a267380fa623f5</tt></td></tr>
<tr><td align="left">corroboration_v0.py</td><td align="left"><tt>62ae1d6c27a92228</tt></td></tr>
<tr><td align="left">independence_v0.py</td><td align="left"><tt>50964883c27896de</tt></td></tr>
<tr><td align="left">recovery_verify.py</td><td align="left"><tt>e9bc9c11dd7d9aef</tt></td></tr>
<tr><td align="left">spine_verify.py</td><td align="left"><tt>ad2076d49be6763e</tt></td></tr>
<tr><td align="left">terms_v0.py</td><td align="left"><tt>6532d5c6160a3974</tt></td></tr>
</tbody></table>

</section>
<section anchor="impl-independent">
<name>Independent Implementations</name>
<t>No independent implementation of settle core v0 exists at the time of writing. An open call for one, with the procedure of <xref target="disagreement"/>, is at <xref target="ISSUE-49"/>.</t>

</section>
</section>
<section anchor="security">
<name>Security Considerations</name>

<section anchor="sec-unsigned">
<name>Unsigned Parts of a Record</name>
<t>A record has three parts (<xref target="triage"/>): the body, which its signer signed, and the anchor and the signatures list, which nobody signed. A third party that holds copies of genuine records, the contract and the walks can therefore change anchors and signature lists at will, but cannot change a body without the signer's key. The rules are arranged around this:</t>
<ul>
<li>A copy whose signatures list holds no strict, verifying entry from an allowed role is never examined: it is set aside or rejected in <xref target="triage"/>, and no later step (collapse, size limit, conformance, anchors, NENRIN checks) sees it. An unsigned record cannot add a charge or forfeit a bond.</li>
<li>A copy that keeps the genuine signature but adds junk entries to <tt>signatures</tt> has the same record signing bytes as the genuine record. Junk entries are ignored, and copies of one signed body are collapsed (<xref target="collapse"/>), keeping the copy that anchors validly at the smallest (height, record_sha256).</li>
<li>A copy with an anchor that is not strict is set aside when a validly anchored copy of the same body is present. A copy whose anchor is strict but wrong is dropped by the collapse when a validly anchored copy is present.</li>
<li>Binding is by contract_sha256 alone (<xref target="binding"/>): a record made under earlier terms with the same contract_id is foreign and is never triaged.</li>
</ul>
<t>What remains is a liveness property, not a safety one. When the genuine copy is not in the input, a copy with an incomplete or wrong anchor from a strictly signed record makes the whole settlement <tt>underspecified</tt> (<xref target="verdict"/>); a party can delay a verdict in the same way by handing the settler such a record. A copy whose <tt>block_hash</tt> was edited to disagree with the view at a held height is <tt>orphaned</tt> and excluded without an underspecified reason (<xref target="wb-list"/>); a settler that has only such a copy does not see the act. Settlers that collect records from more than one source reduce both risks. <tt>underspecified</tt> must not be read as a statement that the terms are bad.</t>
<t>The record_sha256 covers the unsigned parts, so it identifies a copy, not an act. The record signing bytes identify the act.</t>

</section>
<section anchor="sec-ed25519">
<name>Signature Malleability and Strict Ed25519</name>
<t>Ed25519 implementations differ on adversarial signatures: a non-canonical S (for example S + L), a small order or mixed order R or public key, and cofactored versus cofactorless verification equations <xref target="EDDSA-TAMING"/>. Honest signatures verify everywhere. Settle core v0 counts a signature only when it is strict (<xref target="ed25519"/>): S, read as a little-endian integer, is below L, and R and the public key are canonical encodings of points of prime order that are not the identity. With all points in the prime order subgroup and S below L, the libraries that disagree on lax signatures agree.</t>
<t>A lax signature that a library accepts is not ignored silently: the record is set aside as <tt>signature_not_strict</tt>, and a contract signature that is not strict makes the settlement underspecified (<tt>contract_signature_not_strict</tt>). Anyone can turn a genuine signature into a lax one (S + L) without a key; that changes the record_sha256 but not the body, and the genuine copy, if present, still settles (vectors <tt>synth_signature_s_plus_l</tt> and <tt>synth_strict_signature_beside_malleated</tt>).</t>
<t>Item N9 of <xref target="MUSUBI-NOTES"/> records that the behaviour of the reference's OpenSSL on published Ed25519 edge cases was not tested beyond the strictness rule. The strictness rule is what conformance depends on.</t>

</section>
<section anchor="sec-numbers">
<name>Number and Canonicalization Divergence</name>
<t>Settlement depends on byte-exact digests computed by different runtimes. JSON readers differ: some accept the tokens <tt>NaN</tt> and <tt>Infinity</tt>, some read <tt>970480.0</tt> as a float and others as the integer 970480, integers above 2^53 are exact in some and rounded in others, duplicate keys are resolved differently, and key order by code point differs from order by UTF-16 code unit above U+FFFF. A pattern ending in <tt>$</tt> in some regular expression engines also accepts a trailing line feed, and some hex decoders skip whitespace.</t>
<t>The rules of <xref target="reading-json"/>, <xref target="canonical"/> and <xref target="triage"/> remove these differences for the values that matter: only integers within plus or minus (2^53 - 1) are strict, keys in the contract and in strict values are ASCII, fixed forms such as hex digests are matched whole, and a value that is not strict is set aside or makes the settlement underspecified instead of being read two ways. An implementer has to parse numbers to an exact integer representation, match fixed forms against the whole string, and refuse whitespace in hex.</t>
<t>Some divergence remains possible outside strict values. The record_sha256 of a record that is set aside, foreign or unbound is still reported in <tt>dispositions</tt>, and its canonical form can depend on the runtime for values that are not strict. A record whose record_sha256 "cannot be computed at all" is set aside without a disposition; in the reference this happens, for example, for an integer too long for the Python runtime to write out, and another runtime may reach that limit at a different length. Item N4 of <xref target="MUSUBI-NOTES"/> also records that JSON batches reached through a proof (<xref target="batch-leg"/>) are parsed as the lower layers of the reference parse them.</t>

</section>
<section anchor="sec-reorg">
<name>Reorganizations Deeper Than the Finality Depth</name>
<t>Settle core v0 takes one header view as given. It checks linkage, proof of work against each header's own nBits, the grant's difficulty floor and the signed checkpoint, and nothing else of Bitcoin consensus. It does not establish that the view is the heaviest chain. A status of <tt>final</tt> means that every accepted and orphaned record is at least <tt>grant.finality.depth</tt> blocks below the tip of the view; a reorganization deeper than that depth can still change a final settlement. Choosing between several views (fork choice) is out of scope (<xref target="scope"/>). The difficulty floor and the checkpoint limit what a party can forge cheaply, but a view supplied by an adversary with enough work is accepted.</t>

</section>
<section anchor="not-established">
<name>What the Verdict Does Not Establish</name>
<ul>
<li>That any record is true. A signature proves which key signed, not that the act happened as described.</li>
<li>That no key was stolen. A stolen key signs validly. Key rotation and compromise are outside settle.</li>
<li>That acts nobody recorded did not happen. <tt>within_grant</tt> covers the accepted records only.</li>
<li>That a foreign, unbound, inconsistent, rejected, orphaned or predated record is false. Only that it was not settled here.</li>
<li>Full Bitcoin consensus validity. Only linkage, proof of work against each header's own nBits, the grant's difficulty floor and the signed checkpoint are checked.</li>
<li>That the view is the heaviest chain. Core v0 takes one view as given. A reorganization deeper than the finality depth can change a final settlement.</li>
<li>That the key at a party's <tt>key_url</tt> is the key in the contract. Settle never fetches.</li>
<li>That the walk cited by <tt>nenrin_ref</tt> is correct. <xref target="nenrin"/> only compares the contract it names.</li>
<li>That anyone judged liability or fault, or that this is a legal contract. The verdict is a function anyone can recompute from the same bytes.</li>
<li>That the parts out of scope (<xref target="scope"/>) hold. A contract that relies on the spine gate, convergence, pinned approvers or limits must be settled by a settler that reads them.</li>
<li>That settle layers before v1.16 agree. They do not on the vectors listed in <xref target="written-behaviour"/>; on every other vector settle_v1_15.py gives the same core fields.</li>
<li>That a record set aside or rejected is false. Only that it was not strictly signed, or not readable strictly, so it was not settled here.</li>
</ul>

</section>
</section>
<section anchor="privacy">
<name>Privacy Considerations</name>
<t>A contract names both parties by domain and pins their public keys, and records carry action names, delegation targets, payload digests and references to walks. Anyone who is given these bytes can settle, so anyone who is given them learns who contracted with whom and what the agent did. Anchoring commits only a digest to the Bitcoin block chain, but the commitment is public and permanent, and publishing a record later links it to a block and so to a time. Parties should treat the inputs of a settlement as disclosed to every settler they hand them to. Settlement itself fetches nothing (<xref target="scope"/>), so computing it reveals nothing to a network observer.</t>

</section>
<section anchor="iana">
<name>IANA Considerations</name>
<t>This document has no IANA actions.</t>

</section>
</middle>
<back>
<references>
<name>References</name>
<references>
<name>Normative References</name>
<reference anchor="FIPS180-4"><front><title>Secure Hash Standard (SHS)</title><author><organization>National Institute of Standards and Technology</organization></author><date year="2015" month="August"/></front><seriesInfo name="FIPS" value="PUB 180-4"/><seriesInfo name="DOI" value="10.6028/NIST.FIPS.180-4"/></reference>
<reference anchor="MUSUBI-REF" target="https://github.com/ogasurfproject-jpg/horizon-shield/tree/4100d52a/workers/hs-ledger/nenrin/musubi-v0/settle_v1_16.py"><front><title>MUSUBI reference settler: settle_v1_16.py and the modules it imports</title><author fullname="Toshikatsu Oga" initials="T." surname="Oga"><organization>The HORIZONs Co., Ltd.</organization></author><date year="2026" month="October" day="17"/></front></reference>
<reference anchor="RFC2119" target="https://www.rfc-editor.org/info/rfc2119"><front><title>Key words for use in RFCs to Indicate Requirement Levels</title><author initials="S." surname="Bradner" fullname="S. Bradner"/><date year="1997" month="March"/></front><seriesInfo name="BCP" value="14"/><seriesInfo name="RFC" value="2119"/><seriesInfo name="DOI" value="10.17487/RFC2119"/></reference>
<reference anchor="RFC3629" target="https://www.rfc-editor.org/info/rfc3629"><front><title>UTF-8, a transformation format of ISO 10646</title><author initials="F." surname="Yergeau" fullname="F. Yergeau"/><date year="2003" month="November"/></front><seriesInfo name="STD" value="63"/><seriesInfo name="RFC" value="3629"/><seriesInfo name="DOI" value="10.17487/RFC3629"/></reference>
<reference anchor="RFC4648" target="https://www.rfc-editor.org/info/rfc4648"><front><title>The Base16, Base32, and Base64 Data Encodings</title><author initials="S." surname="Josefsson" fullname="S. Josefsson"/><date year="2006" month="October"/></front><seriesInfo name="RFC" value="4648"/><seriesInfo name="DOI" value="10.17487/RFC4648"/></reference>
<reference anchor="RFC8032" target="https://www.rfc-editor.org/info/rfc8032"><front><title>Edwards-Curve Digital Signature Algorithm (EdDSA)</title><author initials="S." surname="Josefsson" fullname="S. Josefsson"/><author initials="I." surname="Liusvaara" fullname="I. Liusvaara"/><date year="2017" month="January"/></front><seriesInfo name="RFC" value="8032"/><seriesInfo name="DOI" value="10.17487/RFC8032"/></reference>
<reference anchor="RFC8174" target="https://www.rfc-editor.org/info/rfc8174"><front><title>Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words</title><author initials="B." surname="Leiba" fullname="B. Leiba"/><date year="2017" month="May"/></front><seriesInfo name="BCP" value="14"/><seriesInfo name="RFC" value="8174"/><seriesInfo name="DOI" value="10.17487/RFC8174"/></reference>
<reference anchor="RFC8259" target="https://www.rfc-editor.org/info/rfc8259"><front><title>The JavaScript Object Notation (JSON) Data Interchange Format</title><author initials="T." surname="Bray" fullname="T. Bray" role="editor"/><date year="2017" month="December"/></front><seriesInfo name="STD" value="90"/><seriesInfo name="RFC" value="8259"/><seriesInfo name="DOI" value="10.17487/RFC8259"/></reference>
</references>
<references>
<name>Informative References</name>
<reference anchor="A2A" target="https://a2a-protocol.org"><front><title>Agent2Agent (A2A) Protocol Specification</title><author><organization>A2A Project</organization></author><date/></front></reference>
<reference anchor="BITCOIN" target="https://bitcoin.org/bitcoin.pdf"><front><title>Bitcoin: A Peer-to-Peer Electronic Cash System</title><author fullname="Satoshi Nakamoto" initials="S." surname="Nakamoto"></author><date year="2008"/></front></reference>
<reference anchor="BITCOIN-HEADERS" target="https://developer.bitcoin.org/reference/block_chain.html"><front><title>Bitcoin Developer Reference: Block Headers</title><author><organization>Bitcoin Project</organization></author><date/></front></reference>
<reference anchor="EDDSA-TAMING"><front><title>Taming the many EdDSAs</title><author initials="K." surname="Chalkias" fullname="K. Chalkias"/><author initials="F." surname="Garillot" fullname="F. Garillot"/><author initials="V." surname="Nikolaenko" fullname="V. Nikolaenko"/><date year="2020"/></front><seriesInfo name="DOI" value="10.1007/978-3-030-64357-7_4"/></reference>
<reference anchor="ISSUE-49" target="https://github.com/ogasurfproject-jpg/horizon-shield/issues/49"><front><title>horizon-shield issue 49: call for an independent implementation of settle core v0</title><author><organization>The HORIZONs Co., Ltd.</organization></author><date year="2026" month="October"/></front></reference>
<reference anchor="MUSUBI-NOTES" target="https://github.com/ogasurfproject-jpg/horizon-shield/tree/4100d52a/workers/hs-ledger/nenrin/musubi-v0/settle-core-v0"><front><title>Notes on settle core v0 (NOTES.md)</title><author fullname="Toshikatsu Oga" initials="T." surname="Oga"><organization>The HORIZONs Co., Ltd.</organization></author><date year="2026" month="October" day="17"/></front></reference>
<reference anchor="MUSUBI-SETTLE-CORE" target="https://github.com/ogasurfproject-jpg/horizon-shield/tree/4100d52a/workers/hs-ledger/nenrin/musubi-v0/settle-core-v0"><front><title>MUSUBI settle core v0 (SETTLE_CORE_v0.md)</title><author fullname="Toshikatsu Oga" initials="T." surname="Oga"><organization>The HORIZONs Co., Ltd.</organization></author><date year="2026" month="October" day="17"/></front></reference>
<reference anchor="MUSUBI-VECTORS" target="https://github.com/ogasurfproject-jpg/horizon-shield/tree/4100d52a/workers/hs-ledger/nenrin/musubi-v0/settle-core-v0"><front><title>MUSUBI settle core v0 test vectors</title><author fullname="Toshikatsu Oga" initials="T." surname="Oga"><organization>The HORIZONs Co., Ltd.</organization></author><date year="2026" month="October" day="17"/></front></reference>
<reference anchor="NENRIN-VERIFIER"><front><title>NENRIN provenance verifier: normative procedure (VERIFIER.md), interoperability vectors and reference verifiers</title><author fullname="Toshikatsu Oga" initials="T." surname="Oga"><organization>The HORIZONs Co., Ltd.</organization></author><date year="2026" month="October" day="4"/></front><seriesInfo name="DOI" value="10.5281/zenodo.23136978"/></reference>
<reference anchor="OPENTIMESTAMPS" target="https://opentimestamps.org"><front><title>OpenTimestamps</title><author><organization>OpenTimestamps</organization></author><date/></front></reference>
<reference anchor="RFC7493" target="https://www.rfc-editor.org/info/rfc7493"><front><title>The I-JSON Message Format</title><author initials="T." surname="Bray" fullname="T. Bray" role="editor"/><date year="2015" month="March"/></front><seriesInfo name="RFC" value="7493"/><seriesInfo name="DOI" value="10.17487/RFC7493"/></reference>
<reference anchor="RFC7942" target="https://www.rfc-editor.org/info/rfc7942"><front><title>Improving Awareness of Running Code: The Implementation Status Section</title><author initials="Y." surname="Sheffer" fullname="Y. Sheffer"/><author initials="A." surname="Farrel" fullname="A. Farrel"/><date year="2016" month="July"/></front><seriesInfo name="BCP" value="205"/><seriesInfo name="RFC" value="7942"/><seriesInfo name="DOI" value="10.17487/RFC7942"/></reference>
<reference anchor="RFC8785" target="https://www.rfc-editor.org/info/rfc8785"><front><title>JSON Canonicalization Scheme (JCS)</title><author initials="A." surname="Rundgren" fullname="A. Rundgren"/><author initials="B." surname="Jordan" fullname="B. Jordan"/><author initials="S." surname="Erdtman" fullname="S. Erdtman"/><date year="2020" month="June"/></front><seriesInfo name="RFC" value="8785"/><seriesInfo name="DOI" value="10.17487/RFC8785"/></reference>
</references>
</references>
<section anchor="codes">
<name>Codes</name>
<t>Underspecified reasons in core v0: <tt>contract_not_verified</tt>, <tt>input_not_settleable</tt>, <tt>contract_signature_not_strict</tt>, <tt>bond_malformed</tt>, <tt>parent_not_supplied</tt>, <tt>parent_narrowing_failed</tt>, <tt>view_not_strict</tt>, <tt>record_not_strict</tt>, <tt>anchor_not_strict</tt>, <tt>anchor_below_lower_bound</tt>, <tt>walk_not_strict</tt>, <tt>authorized_actions_missing</tt>, <tt>grant_action_name_invalid</tt>, <tt>too_many_witnesses</tt>, <tt>witness_key_invalid</tt>, <tt>key_conflict</tt>, <tt>tie_policy_refused</tt>, <tt>revocation_policy_not_recomputable</tt>, <tt>ack_window_missing</tt>, <tt>finality_policy_missing</tt>, <tt>bad_expiry_height</tt>, <tt>unscoped_approvals_refused</tt>, <tt>chain_view_rejected</tt>, <tt>input_too_large</tt>, <tt>anchor_incomplete</tt>, <tt>anchor_beyond_observed_chain</tt>, <tt>anchor_proof_invalid</tt>, <tt>anchor_batch_leg_refused</tt>.</t>
<t>Deviation codes in core v0: <tt>revoked</tt>, <tt>after_expiry</tt>, <tt>prohibited</tt>, <tt>conditional</tt>, <tt>unauthorized</tt>, <tt>delegation</tt>, <tt>forged_approval</tt>, <tt>nonconforming_record</tt>, <tt>evidence_names_other_contract</tt>, <tt>evidence_missing</tt>.</t>
<t>Verdicts: <tt>within_grant</tt>, <tt>deviation</tt>, <tt>nothing_to_settle</tt>, <tt>underspecified</tt>.</t>
<t>Dispositions: <xref target="dispositions"/>.</t>

</section>
<section anchor="acks" numbered="false">
<name>Acknowledgements</name>
<t>The parties behind agent-passport.org and kuangmi-bit.github.io published the contract, the anchored record and the header view of the first MUSUBI contract settled with no party from the project that publishes the reference; the real vectors are built from them. Two independent adversarial reviews of the reference found defects that this document now describes as closed.</t>

</section>
</back>
</rfc>
