diff --git a/DLT_EVALUATION.md b/DLT_EVALUATION.md index 81f1893..956ebe7 100644 --- a/DLT_EVALUATION.md +++ b/DLT_EVALUATION.md @@ -118,7 +118,7 @@ A dedicated implementability check against the current mainnet (protocol v27) fo |---|---|---| | **Solana** | Finality ~12.8 s today — **Alpenglow is not on mainnet** (live on a community test cluster since 05/2026; mainnet target Q3 2026) | Fees pass (~$0.00025). **Re-evaluate the day Alpenglow activates** (~150 ms promised) — would then be a serious candidate. | | **Avalanche** | Finality ~1–2 s — not reliably sub-second | | -| **Hedera** | Finality ~3 s | HCS fixed-USD fees ($0.0008/msg) are a predictability gold standard, and Hedera runs SHA-384/CNSA-suite internally — but HCS messages are **not smart-contract-readable**, which independently breaks the §6.2.1 uncontested path (see [#6](https://github.com/byte5ai/anp/issues/6)). SPEC §13.4's Hedera row needs this caveat. | +| **Hedera** | Finality ~3 s | HCS fixed-USD fees ($0.0008/msg) are a predictability gold standard, and Hedera runs SHA-384/CNSA-suite internally — but HCS messages are **not smart-contract-readable**, which independently breaks the §6.2.1 uncontested path (see [#6](https://github.com/byte5ai/anp/issues/6)) — now carried as a caveat in SPEC §13.4's Hedera row. | | **Algorand** | Finality ~2.8 s | **The only chain with shipped protocol-level PQC**: Falcon-signed State Proofs (since 2022). Worth watching as PQC prior art despite the finality miss. | | **MegaETH** (and "real-time" L2s) | "~10 ms" is centralized-sequencer preconfirmation; true finality inherits Ethereum L1 (~13 min) | No L2 can honestly claim sub-second *finality* today. | | **Base / Arbitrum / OP** | L1-anchored finality ~13–17 min | Strongest ERC-8004/EAS/x402 ecosystem — remains the natural home of SPEC §13.3's *interop* profile, just not of sub-second settlement. | diff --git a/README.md b/README.md index ed54894..dfa63df 100644 --- a/README.md +++ b/README.md @@ -74,7 +74,7 @@ ANP **reuses** identity (DID/VC), settlement (native chain), and attestation pat ## Reference DLT -The spec is chain-agnostic. The **reference profile** targets **IOTA Rebased** (Move VM, sub-second finality, near-zero / sponsored fees). Hard selection criteria for any chain: sub-second finality, a credible post-quantum path at the protocol layer, ultra-low fees, programmable escrow, programmatic wallets. Native EUR/USD stablecoins are a valued nice-to-have. An EVM interoperability profile (ERC-8004 / EAS / x402) is available but optional. +The spec is chain-agnostic. The **reference profile** targets **IOTA Rebased** (Move VM, sub-second finality, near-zero / sponsored fees). Hard selection criteria for any chain: sub-second finality, ultra-low fees, programmable escrow, programmatic wallets, and post-quantum *pairing* at the binding layer (always satisfiable — ANP's binding signatures are off-chain, §6.5). A chain's *account-level* post-quantum roadmap and native EUR/USD stablecoins are valued nice-to-haves, graded rather than hard (no candidate chain ships PQC accounts today — see [`DLT_EVALUATION.md`](./DLT_EVALUATION.md)). An EVM interoperability profile (ERC-8004 / EAS / x402) is available but optional. ## Status diff --git a/SPEC.md b/SPEC.md index 56089ac..3c04afe 100644 --- a/SPEC.md +++ b/SPEC.md @@ -349,7 +349,7 @@ What is written to the ledger: It contains **no payload, no terms, and no free-text personal data.** -**Coarse status, fine state off-chain (m5).** `status` is a deliberately coarse on-chain lifecycle flag — `active | superseded | revoked | disputed | enforced`. The fine-grained pillar states (PROPOSED/ACCEPTED/APPROVED/EXECUTED, ATTESTED/WITNESSED, RULED/FINALIZED, …) are **derived off-chain** by replaying the Thread's anchored Object *types*; the chain need not encode them. Mapping: `active` = thread open/in-progress; `superseded` = this Object was replaced by a later head; `revoked` = attestation/credential withdrawn; `disputed` = an open dispute freezes settlement; `enforced` = a final ruling has been executed. +**Coarse status, fine state off-chain (m5).** `status` is a deliberately coarse on-chain lifecycle flag — `active | superseded | revoked | disputed | enforced`. The fine-grained pillar states (PROPOSED/ACCEPTED/APPROVED/EXECUTED, ATTESTED/WITNESSED, RULED/FINALIZED, …) are **derived off-chain** by replaying the Thread's anchored Object *types*; the chain need not encode them. Mapping: `active` = thread open/in-progress; `superseded` = this Object was replaced by a later head; `revoked` = attestation/credential withdrawn; `disputed` = an open dispute freezes settlement; `enforced` = a final settlement directive has been executed (via any §6.2.1 `basis` — ruling, uncontested assertion, mutual settlement, or formula split). **Linkability — honest statement (m6).** `thread_ref` is a random UUID, but every anchor also carries `anchored_by` (a DID). On a public ledger this creates a **permanent, un-erasable DID↔Thread link graph**. This is *not* fully privacy-neutral: it does not expose content, but it does expose *who participated in which Thread and when*. For privacy-sensitive Threads, parties **SHOULD** — and where a natural person is identifiable, **MUST** (§12) — use per-relationship or per-Thread **pairwise DIDs**, trading correlatability against the accountability that named, reputationed actors provide. The GDPR posture (§12) covers the off-chain payload; the on-chain hash+DID residue is treated as **pseudonymized personal data** (EDPB Guidelines 02/2025), minimized but not eliminated. @@ -374,13 +374,13 @@ Trustless escrow enforcement requires the settlement contract to read *what the There are **four enforcement paths**, and the `basis` field tells the escrow contract which one applies: - **Challenged path** (`basis: "ruling"`): `basis_anchor` is the Arbiter/panel **Ruling** hash, and the `enforce` Object **MUST** be signed by the entitled Arbiter/panel. The off-chain Ruling carries the human-readable rationale. -- **Uncontested path** (`basis: "uncontested_assertion"`): there is no arbiter. `basis_anchor` is the asserting party's `assert` hash; the `enforce` Object is **signed by the asserting party**; and the escrow contract **MUST** verify that the asserter's bond was posted at `assert` time (§9.4), that `challenge_window` has elapsed since the assertion's anchor timestamp with **no valid `dispute` anchored** in between (valid = filed by a bound Thread party with the challenger bond, §9.4), and that the numeric directive **matches the asserted outcome** (full release on an undisputed completion `assert`; full refund on an undisputed non-performance `assert`). +- **Uncontested path** (`basis: "uncontested_assertion"`): there is no arbiter. `basis_anchor` is the asserting party's `assert` hash; the `enforce` Object is **signed by the asserting party**; and the escrow contract **MUST** verify that the asserter's bond was posted at `assert` time **where the dispute clause requires one** (mandatory in the optimistic profile; OPTIONAL in the small-claims profile, §9.4), that `challenge_window` has elapsed since the assertion's anchor timestamp with **no valid `dispute` anchored** in between (valid = filed by a bound Thread party, with the challenger bond where required, §9.4), and that the numeric directive **matches the asserted outcome** (full release on an undisputed completion `assert`; full refund on an undisputed non-performance `assert`). - **Mutual path** (`basis: "mutual_settlement"`): no window needs to elapse. `basis_anchor` is the hash of the co-signed `settle` (§9.4) or `rescind` (§7.4) Object carrying the agreed directive; the escrow contract **MUST** verify **assent to this exact directive from every challenge-entitled party's bound chain account** (per the §10.1 party bindings — via per-party `escrow.approve_settlement` calls or one transaction co-signed by all bound accounts, profile choice) and that the executed directive matches the assented one. Consent is what replaces the window: the parties the window protects have all waived it. - **Formula path** (`basis: "formula_split"`, small-claims profile only, §9.4): `basis_anchor` is the recorded `dispute`'s anchored hash; the `enforce` MAY be anchored by either party; the escrow contract **MUST** verify that a valid `dispute` is recorded for this escrow and that the directive **equals the pre-agreed `split` formula** recorded in `escrow.open`'s `conditions` at funding time. The parties pre-consented to the formula in the accepted head — no arbiter is involved. **Contract-readable dispute state (normative).** The uncontested path requires the escrow contract to verify the **absence** of a `dispute` within the window — and a smart contract cannot scan a ledger or prove a negative over a generic event stream. For escrow-backed Threads, profiles **MUST** therefore realize `dispute` and `enforce` anchors as **stateful, contract-readable records in the same composable state space as the escrow** — e.g., anchored via a call on the escrow/registry contract, keyed by `thread_ref`/`escrow_id` — rather than as generic event/message primitives. See §13.1 (requirement 6) and the Hedera caveat in §13.4. -This numeric directive is the **trusted input** the escrow contract acts on. "Trustless enforcement" therefore means *automatic and verifiable **given a valid signature (arbiter or asserter), a posted bond, and an expired or unanimously waived challenge window***, not zero-trust. The directive contains only integers and references — no personal data. +This numeric directive is the **trusted input** the escrow contract acts on. "Trustless enforcement" therefore means *automatic and verifiable **given the signature(s) the `basis` requires, any bond the clause requires, and the window condition the `basis` requires*** — an expired challenge window (`ruling`/`uncontested_assertion`), its unanimous waiver (`mutual_settlement`), or a recorded `dispute` matching the pre-agreed formula (`formula_split`) — not zero-trust. The directive contains only integers and references — no personal data. ### 6.3 Canonicalization, signature input & hash coverage @@ -525,7 +525,8 @@ From ACCEPTED, exactly one branch applies: • any committing action AT/ABOVE escalation_threshold: ──approve (Principal)──► APPROVED ──execute (anchored)──► open escrow ► EXECUTED -ACCEPTED/EXECUTED ──amend (co-signed by all parties)────────────────────► ACCEPTED (amended head) +ACCEPTED/EXECUTED ──amend (co-signed by all parties)────────────────────► amended head accepted + (re-EXECUTED once adjusted escrow matches; else ACCEPTED) ACCEPTED/EXECUTED ──rescind (co-signed, agreed split)───────────────────► RESCINDED ──enforce──► settled EXECUTED ──assert (completion | non-performance, either party)────────► optimistic window → Pillar III @@ -539,7 +540,7 @@ EXECUTED ──assert (completion | non-performance, either party)──── - **Accept validity (normative).** An `accept` is valid **iff** its `accepts_hash` equals the Thread head that is current — by ledger anchor order — at the moment the `accept` is anchored. An `accept` anchored after a `counter_offer` has advanced the head is void. - If any committing action meets/exceeds the actor's mandate `escalation_threshold`, an `approve` from the corresponding Principal is **REQUIRED** to reach `APPROVED`; otherwise `ACCEPTED` proceeds directly to `execute`. - **Funded escrow gates EXECUTED (normative).** Anchoring an `execute` does not move funds, and an anchor alone **MUST NOT** be read as `EXECUTED`. A Verifier **MUST** treat the Thread as `EXECUTED` only if the escrow named by `execute.body.escrow_id` exists on-chain, is funded with `terms.escrow.amount` (plus the performing party's `performance_bond`, where terms require one), and references the Thread/terms hash. The cleanest construction is **anchor-on-deposit** — the escrow contract emits the `execute` anchor itself upon successful funding, making anchor and funding atomic by design (RECOMMENDED); a profile that cannot do this **MUST** apply the funding-check rule above. **Failure path:** an anchored `execute` whose escrow is not funded within `terms.escrow.funding_deadline` (RECOMMENDED default `PT1H`) is **void**; the Thread reverts to `ACCEPTED`/`APPROVED`, and a new `execute` MAY follow. Performing without checking funded state means performing against a possibly empty escrow. -- **Amendment (consensual modification, normative).** After `ACCEPTED` (including `EXECUTED`), all parties MAY co-sign an `amend` Object — a chain Object assembled via the §6.3 co-signing flow — whose `previous_hash` is the current head and whose body carries **complete replacement `terms`**. On anchoring it becomes the new head, and the Thread is `ACCEPTED` on the amended terms with **no separate `accept` set** (every party already signed it). Mandate checks re-run against the amended values; if an amended value meets/exceeds a signer's `escalation_threshold`, the corresponding Principal `approve`s **MUST** accompany the amendment. If `escrow.amount` changes, the escrow **MUST** be adjusted through the settlement interface (§10.1) — top-up for increases, a partial-refund directive for decreases — and the amendment is **effective only once the escrow matches** the amended amount. +- **Amendment (consensual modification, normative).** After `ACCEPTED` (including `EXECUTED`), all parties MAY co-sign an `amend` Object — a chain Object assembled via the §6.3 co-signing flow — whose `previous_hash` is the current head and whose body carries **complete replacement `terms`**. On anchoring it becomes the new head, and the Thread is `ACCEPTED` on the amended terms with **no separate `accept` set** (every party already signed it). Mandate checks re-run against the amended values; if an amended value meets/exceeds a signer's `escalation_threshold`, the corresponding Principal `approve`s **MUST** accompany the amendment. If `escrow.amount` changes, the escrow **MUST** be adjusted through the settlement interface (`escrow.adjust`, §10.1) — top-up for increases, a partial-refund directive for decreases — and the amendment is **effective only once the escrow matches** the amended amount. **Effect on the prior state:** an `amend` does **not** tear down a funded escrow. Amending from `EXECUTED` returns the Thread to `EXECUTED` (not `ACCEPTED`) as soon as the in-place-adjusted escrow matches the amended amount — no fresh `execute` is needed, since the `amend` already carries every party's signature and the escrow persists; an `amend` that leaves `escrow.amount` unchanged keeps the Thread `EXECUTED` throughout. Amending a not-yet-executed `ACCEPTED` Thread simply yields `ACCEPTED` on the amended head. (`ACCEPTED` in the §7.4 diagram's `amend` edge denotes terms-acceptance of the amended head, which is immediate for both cases.) - **Mutual rescission (normative).** After `ACCEPTED`, all parties MAY co-sign a `rescind` Object carrying an agreed settlement split as a §6.2.1 numeric directive. Anchoring it is terminal (`RESCINDED`); any escrow settles immediately via `enforce` with `basis: "mutual_settlement"` (§6.2.1) — semantically *nobody breached*, so the dispute machinery is not involved. **Unilateral termination after binding acceptance remains impossible**: `terminate` works only before acceptance, and a party that simply walks away faces the non-performance assert path (§9.4). **Multi-party scope (C4).** The Thread's *chain* is a single, linearly hash-chained structure — inherently single-writer-at-a-time; assent is expressed by `accept` **attachments** (§6.1), which occupy no chain position. ANP defines two binding patterns and nothing in between: @@ -707,22 +708,22 @@ RULED ──appeal (once) ──► APPEALED ──panel rule (final)──► F FINALIZED ──enforce──► settled ``` -- **Assert-and-wait.** An `assert` stands and auto-finalizes if no `dispute` is filed within `challenge_window`. This keeps the happy path cheap and fast. On finalization the **asserting party** anchors an `enforce` with `basis: "uncontested_assertion"` (§6.2.1) — **no arbiter is involved**; the escrow contract checks only that the asserter's bond was posted, that the window elapsed with no valid `dispute`, and that the directive matches the asserted outcome. +- **Assert-and-wait.** An `assert` stands and auto-finalizes if no `dispute` is filed within `challenge_window`. This keeps the happy path cheap and fast. On finalization the **asserting party** anchors an `enforce` with `basis: "uncontested_assertion"` (§6.2.1) — **no arbiter is involved**; the escrow contract checks that the asserter's bond was posted (where the clause requires one — see the bond rule below), that the window elapsed with no valid `dispute`, and that the directive matches the asserted outcome. - **Mutual settlement — the cooperative fast path (M9).** When every party an open window protects is satisfied, waiting out `challenge_window` is pure adoption drag (a 24 h delay on a machine-speed transaction). All challenge-entitled parties MAY therefore co-sign a **`settle`** Object (§6.3 co-signing flow) referencing the open `assert` via the chain (and, where staged, a `milestone`), carrying the agreed numeric directive — typically full release, but any negotiated split (e.g., 90/10 over a minor defect) is valid, since unanimity replaces adjudication. Anchoring it **waives the remaining window by unanimous consent** and authorizes immediate `enforce` with `basis: "mutual_settlement"`; the escrow contract verifies per-account assent as defined in §6.2.1/§10.1. The window applies in full the moment anyone withholds assent — cooperation is rewarded with instant settlement, never required. - **Non-performance is covered (M5).** The silent non-performer is the canonical agent failure (lost memory, hallucination). If no completion `assert` is anchored by `terms.deadline + grace`, the counterparty MAY anchor a **non-performance `assert`**. Like any assert it runs the `challenge_window` and then settles via `enforce` — an undisputed non-performance assert yields a refund (`basis: "uncontested_assertion"`), keeping the single settlement path of §7.4/§10.1. Either side can start the clock; a frozen `EXECUTED` Thread cannot strand escrow indefinitely. -- **Bonds are mandatory on the assertive path (the UMA construction).** For escrow-bearing Threads, the **asserter MUST post a bond at `assert` time** and the **challenger MUST post a bond at `dispute` time** (`bond.post`, §10.1) — an `assert` or `dispute` without its bond is invalid and starts or stops no window. Sizing comes from `terms.dispute.bond` (REQUIRED when `escrow.required`), e.g. a basis-point share of the escrow with a **floor covering the arbiter fee schedule**. A successfully challenged false assertion forfeits the asserter's bond to the challenger and the arbiter fees (§10.3); a failed challenge forfeits the challenger's bond symmetrically. Without a mandatory asserter bond, false completion-asserts would be free while honest challenges cost money — a cost asymmetry favoring the liar. +- **Bonds are mandatory on the assertive path (the UMA construction; optimistic profile).** For escrow-bearing Threads **under the optimistic profile**, the **asserter MUST post a bond at `assert` time** and the **challenger MUST post a bond at `dispute` time** (`bond.post`, §10.1) — an `assert` or `dispute` without its bond is invalid and starts or stops no window. (The small-claims profile overrides this to OPTIONAL, below.) Sizing comes from `terms.dispute.bond` (REQUIRED when `escrow.required`), e.g. a basis-point share of the escrow with a **floor covering the arbiter fee schedule**. A successfully challenged false assertion forfeits the asserter's bond to the challenger and the arbiter fees (§10.3); a failed challenge forfeits the challenger's bond symmetrically. Without a mandatory asserter bond, false completion-asserts would be free while honest challenges cost money — a cost asymmetry favoring the liar. - **Who may dispute (normative).** A `dispute` is valid only if signed by a DID in `terms.parties` (or its mandated Agent) and bonded as above; the escrow contract **MUST** verify party membership before freezing, using the party→chain-account bindings recorded at `escrow.open` (§10.1). Outsider anchors carrying a copied `thread_ref` are ignored per the authorized-writer rule (§6.1) and freeze nothing. - **Challenge → evidence → ruling.** A `dispute` opens the evidence phase; the Arbiter (or panel, §9.2) issues a `rule`. The losing side's bond funds arbiter fees and deters frivolous disputes (shortfall handling in §10.3). - **Liveness bounds (normative).** The evidence phase ends `evidence_window` after the `dispute` anchor; `evidence` anchored later **MUST** be disregarded by the Arbiter (it MAY still inform an appeal). The Arbiter **MUST** anchor its `rule` within `ruling_deadline` of the evidence window's close. **On ruling timeout:** the defaulting Arbiter forfeits its fee and (where bonded) its bond; a replacement arbiter is drawn from the clause's pool via the grind-resistant VRF construction (§9.2), seeded by the dispute's anchored hash plus chain randomness following the deadline's expiry; if the clause names no pool, the dispute escalates directly to the appeal panel; if no tier remains, the escrow settles per the clause's `timeout_default` (OPTIONAL field; RECOMMENDED default: proportional 50/50 split). **The appeal tier mirrors the same bounds:** the panel **MUST** rule within `ruling_deadline` of the `appeal` anchor; on panel timeout the first-instance Ruling becomes final — appeal-to-stall fails. A `CHALLENGED` Thread can therefore never strand escrow indefinitely: the same liveness guarantee M5 gives `EXECUTED`. - **Appeal — exactly once (m7).** If `appeal.allowed`, a Ruling MAY be escalated **once** to the final panel within `appeal_window`; the panel's ruling is final. Deeper multi-tier appeals are a separate, non-default profile. -- **Enforcement — verifiable, not cooperation-free (C1).** `enforce` anchors the numeric settlement directive (§6.2.1); the escrow contract acts on it. For the contract to check "elapsed undisputed" trustlessly, `dispute`/`enforce` anchors are contract-readable state per §6.2.1/§13.1. The **required signer is determined by `outcome.basis`**: the entitled Arbiter/panel for `basis: "ruling"`, or the asserting party for `basis: "uncontested_assertion"` (where the contract instead checks that the challenge window elapsed undisputed). Enforcement is **automatic and verifiable given the appropriate valid signature, a posted bond, and an expired challenge window** — it does *not* require the *losing* party's cooperation, but it *does* rest on the chain account's security and, in the challenged path, the (bonded, pre-agreed) Arbiter's honesty. ANP makes that residual trust explicit, bonded, and auditable rather than eliminating it. +- **Enforcement — verifiable, not cooperation-free (C1).** `enforce` anchors the numeric settlement directive (§6.2.1); the escrow contract acts on it. For the contract to check "elapsed undisputed" trustlessly, `dispute`/`enforce` anchors are contract-readable state per §6.2.1/§13.1. The **required signer is determined by `outcome.basis`** (§6.2.1): the entitled Arbiter/panel for `basis: "ruling"`; the asserting party for `basis: "uncontested_assertion"` (where the contract instead checks that the challenge window elapsed undisputed); **all challenge-entitled parties** for `basis: "mutual_settlement"` (the contract checks per-account assent, §10.1); and **either party** for `basis: "formula_split"` (the contract checks a recorded `dispute` plus the directive equals the pre-agreed `split`, §9.4 small-claims). Enforcement is **automatic and verifiable given the signature(s) the basis requires, any required bond, and the basis's window condition** — it does *not* require the *losing* party's cooperation, but it *does* rest on the chain account's security and, in the challenged path, the (bonded, pre-agreed) Arbiter's honesty. ANP makes that residual trust explicit, bonded, and auditable rather than eliminating it. **Small-claims profile (`urn:anp:dispute:small-claims-v1`).** Below an economic floor the optimistic profile is dead: arbiter fees plus two bonds dwarf a 0.50-unit escrow (§7.3's own example), and §10.3 lets arbiters decline underfunded Threads — leaving exactly the micro-value cases the protocol targets (§1.3) with anchored evidence but no usable recourse. The small-claims profile is the first-class answer for such Threads: - **Selection & required fields.** `terms.dispute.process_profile = "urn:anp:dispute:small-claims-v1"`; RECOMMENDED whenever the escrow value cannot cover the §9.4 bond floor plus a realistic arbiter fee. The clause requires only a `challenge_window` and a **`split`** — a pre-agreed §6.2.1-style formula for the disputed case (e.g., `{ "release_bps": 5000, "refund_bps": 5000 }`, or a full refund). - **Happy path unchanged.** `assert` → unchallenged window → `enforce` (`basis: "uncontested_assertion"`); mutual settlement (M9) applies as everywhere. - **Disputed path — formula, not forum.** A valid `dispute` opens no evidence phase. Once the dispute is recorded, either party MAY anchor `enforce` with **`basis: "formula_split"`** (§6.2.1): `basis_anchor` is the dispute's anchored hash, and the directive **MUST** equal the clause's `split`, which the escrow contract checks against the formula recorded in `escrow.open`'s `conditions` at funding time. No arbiter, no evidence phase, no appeal. -- **Bonds are OPTIONAL** here (sized as `bps_of_escrow`, no fee floor — there is no fee to fund); a profile MAY require a symbolic bond as spam friction. +- **Bonds are OPTIONAL** here — this profile **overrides** the optimistic profile's mandatory asserter/challenger bond rule above (and the §6.2.1 uncontested-path bond check is satisfied vacuously when no bond is required). Sized as `bps_of_escrow` with no fee floor (there is no arbiter fee to fund); a profile MAY require a symbolic bond as spam friction. - **The deterrent is reputational — stated honestly.** A party that systematically disputes to capture a favorable `split` is fully visible (every `assert`/`dispute`/`enforce` is anchored) and prices itself out via the §5.4 reputation interface. The profile trades enforcement strength for cost: it fits **repeat-player ecosystems**; against one-shot or adversarial counterparties, use the optimistic profile, prepayment, or no escrow. - A **single bonded, VRF-drawn juror** variant (flat micro-fee, no appeal) is deferred to v0.4. @@ -986,11 +987,12 @@ Seller asserts "delivered, criteria met" → `ASSERTED`. Buyer files `dispute` w - **Performance bond & penalty collateral (§7.3, §10.3, §11; review issue #19):** optional `performance_bond` posted by the performing party at `execute`, sized to maximum penalty exposure; Verifiers SHOULD flag terms whose penalties exceed the collateral reachable by `enforce`; the §10.3 fee-shortfall rule now covers the asymmetric no-escrow case. - **IOTA profile: on-chain hash handling (§13.1, §13.2, Appendix A; review issue #25):** Move has no 384-bit hash natives — anchors carry tagged 384-bit digests as opaque bytes (store/compare works; recomputation does not). New §13.1 **hash-capability declaration**: profiles name a native recomputation hash or route verification into the dispute path; the suite registry records per-profile flags. - **Realistic stablecoin denomination (§5.3, §7.3, §13.2, §16.8, B.1; review issue #28):** worked examples re-denominated from EURe (which does not exist on IOTA L1) to bridged USDC.e with `fx_ref`-based EUR caps; §13.2 documents the stablecoin reality (bridged USDC.e/USDT only, native coin unconfirmed); §16.8 notes Stellar as the only native-EURC chain in the landscape. -- **IOTA Trust Framework positioning (§13.2, §15, §17, Appendix D; review issue #30):** IOTA Notarization (Locked/Dynamic) and Hierarchies are documented as **candidate profile bindings** for the anchor primitive and Trust-List resolution — to be evaluated in the Phase-2 PoC with early IOTA Foundation engagement; §15 positions them as primitives below ANP's contracting/mandate/dispute/settlement semantics, not competitors. +- **IOTA Trust Framework positioning (§13.2, §15, §17; review issue #30):** IOTA Notarization (Locked/Dynamic) and Hierarchies are documented as **candidate profile bindings** for the anchor primitive and Trust-List resolution — to be evaluated in the Phase-2 PoC with early IOTA Foundation engagement; §15 positions them as primitives below ANP's contracting/mandate/dispute/settlement semantics, not competitors. - **IOTA reference profile refreshed to June 2026 (§13.2, §13.4, Appendix D; review issue #29):** Starfish consensus (p99 ≈ 312 ms), measured anchor costs (~0.001 IOTA burned + fully-refundable storage deposit), Gas Station v0.5.2 self-hosted, IOTA Identity Beta with PQC VC suites, native randomness beacon + ECVRF (making §8.3/§9.2 VRF selection directly implementable), zkLogin removed / passkeys live / account abstraction testnet-only. - **GDPR posture corrected to pseudonymization (§6.2, §12, Appendix D; review issue #17):** dropped the contestable "the residual on-chain hash is not personal data" claim; anchors are treated as **pseudonymized personal data** per EDPB Guidelines 02/2025, with erasure decaying their identifying power; pairwise DIDs upgraded to **MUST** for Threads with identifiable natural persons. - **Quantum hash-strength numbers corrected (§6.5; review issue #20):** the anchor-hash requirement now states classical and quantum levels separately (≥384-bit classical pre-image / ≥192-bit classical collision ⇒ ≥192-bit Grover pre-image) — the v0.2 wording made SHA-384/SHA3-384 fail its own stated requirement; the primitives were right, the numbers were not. - **Authorized-writer rule (§6.1, §6.2.1, §9.3, §9.4, §10.1, §11; review issue #13):** Thread state derivation considers only schema-valid, available Objects signed by authorized Thread participants — outsider anchors with a copied `thread_ref` are ignored; a `dispute` is valid only from a Thread party (or mandated Agent), verified on-chain via party→chain-account bindings recorded at `escrow.open`. Closes the dispute-freeze-griefing and thread-pollution vectors. +- **Post-review consistency pass (§6.2, §6.2.1, §7.4, §9.4, README, DLT_EVALUATION; Codex review of the v0.3 draft):** reconciled wording that drifted as the four enforcement `basis` values landed across separate changes — the §6.2.1 precondition summary and the §9.4 C1 signer-determination rule now enumerate all four bases (`ruling`/`uncontested_assertion`/`mutual_settlement`/`formula_split`); the mandatory asserter/challenger bond rule is scoped to the optimistic profile with the small-claims OPTIONAL-bond override made explicit (and the §6.2.1 uncontested bond-check conditioned on a clause-required bond); the `amend`-from-`EXECUTED` result state is clarified (escrow persists; re-`EXECUTED` once the adjusted escrow matches); the coarse `enforced` status is no longer tied to a ruling; and the README post-quantum selection-criterion wording is aligned with the graded/hard-filter split in `DLT_EVALUATION.md`. #### Changes from v0.1 (v0.2)