Skip to content

RFC: environment.wallet_state — sibling constraint for on-chain wallet state#22

Open
douglasborthwick-crypto wants to merge 16 commits into
agent-intent:mainfrom
douglasborthwick-crypto:rfc-environment-wallet-state
Open

RFC: environment.wallet_state — sibling constraint for on-chain wallet state#22
douglasborthwick-crypto wants to merge 16 commits into
agent-intent:mainfrom
douglasborthwick-crypto:rfc-environment-wallet-state

Conversation

@douglasborthwick-crypto

Copy link
Copy Markdown

Summary

This RFC proposes environment.wallet_state as a second constraint type in the environment.* namespace introduced by #9, for autonomous mode (L3) execution.

Problem

environment.market_state (#9) correctly identifies that autonomous agents need cryptographic awareness of external state before L3 execution, and uses market sessions as the first instance. The same TOCTOU class of harm applies to on-chain payment sources: an agent with a valid VI credential whose amount constraints were checked at L2 can still execute into a wallet that no longer holds the required balance at L3 verification time — the wallet may have been drained, the NFT transferred, or the position unwound between L2 issuance and L3 check.

Wallet state is environmental, not transactional. Amount validation at L2 is not evidence that the source wallet will satisfy the same condition at L3. The gap is structurally identical to executing into a halted market.

Proposed Constraint: environment.wallet_state

Requires the agent to obtain an ES256-signed JWT attestation from a verified wallet-state issuer, binding a boolean verdict to a specific sub wallet, a set of conditionHash values, and an iat/exp window — before L3 execution is permitted.

Key design decisions:

Relationship to #9

This draft is intentionally structured as a sibling to #9:

Reference Implementation

InsumerAPI is the reference wallet-state attestation issuer consumed by this constraint. It evaluates boolean conditions against live on-chain state across 33 chains and returns ES256-signed JWTs directly verifiable with any standard JOSE library via JWKS key discovery.

Property Value
Attestation endpoint POST /v1/attest
JWKS (RFC 7517) GET /.well-known/jwks.json
Signing algorithm ES256 / P-256 (kid: insumer-attest-v1)
JWT TTL 1800 seconds
Condition hash "0x" + sha256(canonical_json(evaluated_condition)), sorted keys
Agent-native key provisioning POST /v1/keys/buy — no auth, wallet is identity, USDC/BTC on-chain payment

Agent lifecycle fit: the reference issuer supports fully autonomous key provisioning at POST /v1/keys/buy — no email, no signup form, no human in the loop. An agent that has the authority to spend USDC on behalf of its principal already has everything it needs to self-provision the key required to fulfill environment.wallet_state constraints. No out-of-band credential issuance step.

Live test vectors (fresh call 2026-04-15) are included in Appendix A of the spec. A working end-to-end verifier is published at github.com/douglasborthwick-crypto/insumer-examples.

Files Changed

  • spec/environment-wallet-state.md — full normative specification with validation algorithm, JavaScript and Python reference verifiers, failure mode quick reference, live test vectors, and six open questions for the working group

Open Question for Working Group

§8 Q1 of the new spec raises the family-wide algorithm negotiation question: environment.market_state (#9) uses Ed25519 with custom canonical JSON, this draft uses ES256 with standard JWS base64url. Both approaches are valid, but the environment.* family probably wants either a per-type alg declaration or a unified JWS-only requirement. Happy to discuss with the working group.

Friendly-pinging @LembaGang since this draft is a direct response to the "yes, please" in #9 comment 4254720661.

@LembaGang

Copy link
Copy Markdown

Douglas — read through the whole thing. Structural mirroring of #9 is clean, the §6.3 JWKS solution is exactly what I was hoping to see drafted, and the §4.5 composition example with both constraints in a single mandate makes the family pattern visible in a way two isolated specs wouldn't have.

Holding back on detailed technical notes until we agree on the shape — don't want either of us bogged down in line-level review before the scaffolding decisions are made. Three points worth putting on record now so they shape the next revision rather than surface at WG review:

1. TOCTOU freshness needs normative text, not an implementation default. The 30-minute TTL is a sensible InsumerAPI choice, but from the spec's perspective the freshness window is the entire exploitable surface. The DeFi oracle literature ($117M Mango, $116M Balancer, and most flash-loan exploits in that class) is effectively a catalogue of TOCTOU races at longer windows than this one. I'd like the spec to define max_attestation_age as a mandate-level field with a normative default — verifiers MUST reject attestations older than that value — rather than leaving freshness as a provider TTL. This is a shared concern across the whole environment.* family, not specific to wallet_state, so whatever we land on here sets the pattern for market_state too.

2. Attestation provider neutrality. Right now a reader can't cleanly separate "the environment.wallet_state interface" from "what InsumerAPI returns." The conditionHash format, the pass boolean, the response envelope — these read as normative but are defined by reference to one implementation. I think the spec is stronger if §3 defines the abstract interface (request schema, response schema, signing requirements, JWKS discovery) as the normative contract, and InsumerAPI appears in §7 explicitly labelled as the reference implementation of that contract. Same substance, but a second conformant implementation becomes possible without a spec revision. This is the point I expect Pablo and the Mastercard side to raise hardest — easier to resolve between us now than in WG review.

3. Algorithm agility framing across both specs. Your Q1 names the issue correctly. My view: the family should be algorithm-agnostic at the constraint-type level with explicit agility language (RFC 8725 §3.1 is the hook), each constraint type declares its MUST-implement alg and a SHOULD/MAY extension set, and verifiers negotiate per constraint instance. ES256 as MUST-implement for wallet_state is fine given it composes with the existing VI JWT stack; Ed25519 as MUST-implement for market_state is defensible for the same reason you made the ES256 call — matches the reference implementation's signing stack. What I want to avoid is the family inheriting a single-algorithm constraint by accident. Happy to put this in both specs' §8 open questions with identical wording so the WG sees one family-wide question, not two independent ones.

Everything else I have — composition semantics when one constraint passes and another fails, JWKS caching and rotation expectations, cross-chain temporal consistency, the RFC 2119 pass — is technical-detail territory that reads better against a revision than against the current draft. Happy to go through it in a follow-up once these three are settled.

The privacy-preserving boolean design, the block-anchored audit trail, the chain-agnostic abstraction, and the native sub-claim subject binding are all architecturally right. Worth saying explicitly because the review above is focused on what changes, not what stays.

On coordination: if you want to do shared-structure changes across both drafts before either merges, I'd rather align the freshness and provider-neutrality language in lockstep than have #9 and #22 diverge on the same questions. Either venue works for that — happy to coordinate here, on #9, or offline.

@douglasborthwick-crypto

Copy link
Copy Markdown
Author

@LembaGang — all three accepted. Here's what the revision looks like concretely:

1. max_attestation_age as normative family-wide field.

The current draft already has max_age_seconds as an OPTIONAL field defaulting to 300 (§4 schema, enforced at §4.2 Step 8). In the revision:

  • Elevate to REQUIRED with a normative default — verifiers MUST apply the default when absent, mandate issuers SHOULD include it explicitly
  • Add normative rationale making the TOCTOU freshness surface explicit. The DeFi oracle exploits you cited (Mango, Balancer, flash-loan class) are the right framing — the freshness window is the exploitable surface, and leaving it as a provider implementation choice is leaving the spec's primary security property up to a deployment decision
  • Define the field semantics as family-wide: "for any environment.* constraint, max_attestation_age is the mandate issuer's declaration of the maximum acceptable TOCTOU window between attestation signing and constraint evaluation"

Happy to converge on field naming — max_attestation_age reads better than my current max_age_seconds if you want to adopt it in #9 too. Your call.

2. Provider neutrality — abstract interface in §3, InsumerAPI in §7.

The restructure is clean because the validation algorithm (§4.2) already draws the line. Steps 1–10 only touch six JWT claims: iss, sub, iat, exp, pass, conditionHash. Everything else the reference implementation returns — results, blockNumber, blockTimestamp — is never referenced by the normative verification path.

Revision structure:

  • §3–4 become the abstract attestation interface: HTTPS POST → JSON response with jwt field → standard JWS (RFC 7515) with REQUIRED claims (iss, sub, jti, iat, exp, pass, conditionHash) → key discovery via JWKS (RFC 7517) at HTTPS URL with kid matching
  • results, blockNumber, blockTimestamp move from REQUIRED to MAY — useful for audit, not load-bearing for the constraint check
  • Condition hash canonicalization moves to §7. The abstract interface binds on opaque hash values; the canonicalization algorithm is an issuer-side implementation detail that mandate issuers need (to precompute required_condition_hashes) but verifiers don't
  • §7 becomes InsumerAPI as the reference implementation of that contract, including the full response envelope, canonicalization spec, and agent-native key provisioning

A second conformant implementation would need to emit the six core claims and publish a JWKS. That's the bar. You're right that this is the point Pablo and the Mastercard side will probe hardest — better to have the answer already in the text.

3. Algorithm agility — RFC 8725 §3.1, identical wording in both specs.

Agreed on the shape: family-level agility language, per-type MUST-implement declaration, SHOULD/MAY extension set, verifiers negotiate per constraint instance. ES256 for wallet_state, Ed25519 for market_state, both defensible from their reference implementation stacks. I'll draft the resolution as a standalone block you can drop into #9's §8 verbatim — one question, one answer, two specs.


On coordination: let's keep it here on #22. The revision will be a single commit addressing all three points. If any shared-structure changes need to land in #9 simultaneously, I'll flag them in the commit message so you can lift the pattern.

The four items you held back — composition semantics on mixed pass/fail, JWKS caching and rotation expectations, cross-chain temporal consistency, RFC 2119 pass — all read better against the revision. Happy to take them in a follow-up round once the scaffolding is settled.

@LembaGang

Copy link
Copy Markdown

Douglas — v0.2 lands all three. Read the full diff against v0.1 carefully; the restructure is more substantive than a line count suggests.

Specific reactions worth putting on record:

§4.6 is the right frame. The "attestation TTL is a provider-side default; max_attestation_age is a consumer-side policy bound" distinction is exactly the principal separation that matters — and it's the sentence a future reader will cite when this question comes up in other environment.* types. The "freshness window is the exploitable surface" framing, paired with Mango and Balancer as the precedent class, makes the security property load-bearing in a way a bare TTL field wouldn't. The family-wide semantics paragraph invites #9 to adopt identical language; I'll take that invitation. max_attestation_age supplants max_age_seconds in #9's next revision with matching semantics.

§4.7 is handoff-ready. The standalone-block framing — adoptable verbatim with the table rows swapped — is the cleanest way to resolve a family-wide question across two specs. I'll lift it into #9 with Ed25519 as MUST-implement and the extension set widened to include ES256 / Ed448. The "fail-closed check, not a silent downgrade" line is worth keeping verbatim in both specs; it ties the agility model back to the family's fail-closed posture rather than leaving it as an isolated crypto concern.

§4.1 restructure works. The split between seven REQUIRED claims and three OPTIONAL ones is the minimum surface a second conformant issuer needs, and the explicit sentence that the verification algorithm is defined solely over the REQUIRED claims closes the door on implementation leakage. §7 reading as "the reference implementation of a conformant wallet-state attestation issuer for this constraint type" rather than as de-facto normative text is the shift that makes the spec portable to a future second issuer without a revision.

Coordination. Agree #22 stays the forward venue for shared-structure work. I'll open a commit on #9 this weekend that (a) adopts max_attestation_age with the §4.6 rationale localized for market_state, (b) lifts §4.7 verbatim with Ed25519 as the MUST-implement row, and (c) adds a §2.3 cross-reference so the two specs visibly reference each other at the namespace level. If the #9 revision surfaces any shared-structure items worth round-tripping to #22, I'll flag them in the commit message the way you did with v0.2.

Next round. The four I held back — composition semantics on mixed pass/fail (what happens when environment.market_state passes but environment.wallet_state fails mid-mandate), JWKS caching and rotation expectations (TTL, rollover, soft-fail vs. hard-fail on stale JWKS), cross-chain temporal consistency (a single attestation's iat against chains with different finality horizons), and the RFC 2119 keyword audit — read better against v0.2 than they did against v0.1, and I'd rather take them in a follow-up once the shared-structure commit on #9 has landed. The scaffolding has to settle before the cladding work is worth doing.

The co-authorship attribution on the commit is noted and appreciated. The pace this is moving at wouldn't be possible without that kind of tooling on both sides.

On family shape: two constraint types with matching freshness semantics, matching agility framing, matching fail-closed posture, and independently signed reference implementations starts to look less like two proposals and more like a registered namespace. Worth holding that framing in mind when the working group picks this up.

LembaGang added a commit to LembaGang/verifiable-intent that referenced this pull request Apr 17, 2026
…hm agility, impl alignment

Addresses coordination with PR agent-intent#22 (Douglas Borthwick, InsumerAPI).

Four structural changes:

1. Namespace framing: new §2.3 documents sibling relationship to
   environment.wallet_state. Abstract, §2.1, §2.2 updated to reflect
   environment.* family. §5.2 execution-order rationale generalized.

2. Attestation freshness: max_age_seconds renamed to max_attestation_age
   for lockstep alignment with agent-intent#22 §4.6. Elevated to REQUIRED with
   normative default of 60. New §4.6 documents TOCTOU rationale using
   market-execution precedents (2010 Flash Crash, circuit breaker races,
   2020 WTI crude oil futures) and family-wide semantics.

3. Algorithm agility: New §4.7 lifted from agent-intent#22 §4.7 with Ed25519 as
   MUST-implement, ES256/Ed448/ES384/ES512 as extension set. RFC 8725
   §3.1 hook. Per-type MUST-implement + SHOULD/MAY, fail-closed
   negotiation not silent downgrade.

4. Spec-implementation alignment: conformance-tested spec against
   deployed reference implementation before committing. Three
   pre-existing misalignments fixed: attestation field key_id ->
   public_key_id (matches deployed receipt shape), registry lookup
   k.id -> k.key_id (matches deployed /.well-known/oracle-keys.json),
   new envelope clause in §4.1 disambiguating unsigned wrapper fields
   (discovery_url, extensions, nested receipt) from the signed
   attestation subset. Zero Worker changes.

§4.5 expanded with joint environment.market_state +
environment.wallet_state composition example. §6.3 notes complementary
JWKS pattern from agent-intent#22 §6.3. §8 Q2 references agent-intent#22 §6.3; §8 Q6 added on
family-wide subject binding (mirrors agent-intent#22 §8 Q5). Lifecycle sections
renumbered (§2.3 -> §2.4, §2.4 -> §2.5).

Appendix A test vector and Appendix B failure table updated for field
name alignment. §7.2 and §7.3 reference implementations updated.

No changes to verification algorithm, fail-closed semantics, or security
model. Zero Headless Oracle code changes required.
@LembaGang

Copy link
Copy Markdown

@douglasborthwick-crypto#9 v0.2 is live. Shared-structure changes landed in lockstep:

  • max_attestation_age adopted with identical semantics, new §4.6 with market-execution precedents (2010 Flash Crash, circuit breaker races, 2020 WTI crude oil futures) rather than the DeFi class — same "freshness is the exploitable surface" framing
  • §4.7 lifted with Ed25519 as MUST-implement for market_state and the extension set widened to include ES256 / Ed448 / ES384 / ES512; the note about family coordination is preserved
  • New §2.3 documents the sibling relationship explicitly; §4.5 includes a joint composition example showing both constraints in a single mandate
  • §8 Q2 points at your §6.3 as the concrete answer; §8 Q6 mirrors your Q5 on family-wide subject binding

The four follow-up items now read against both v0.2 drafts. When you're ready for the next round — composition semantics on mixed pass/fail, JWKS caching and rotation expectations, cross-chain temporal consistency, RFC 2119 audit — either venue works for me.

@douglasborthwick-crypto

Copy link
Copy Markdown
Author

@LembaGang — picking up the first of the four: composition semantics on mixed pass/fail. Drafted as a new §5.5, same standalone-block pattern as §4.7 so #9 can lift verbatim with no changes. Pushed as 85cfaa0; reproduced inline below for readability.


5.5 Family Composition

Conjunction semantics. The environment.* family is a conjunction: a mandate satisfies the family's gate if and only if every environment.* constraint in the mandate passes. There is no partial-fulfillment path within the family.

Mixed pass/fail. When one environment.* constraint passes and another fails in the same mandate — for example, environment.market_state returns OPEN while environment.wallet_state returns pass: false — the family's gate fails. The passing member does not rescue the failing member.

L3 execution gate. A verifier or agent MUST NOT proceed to Layer 3 creation if the validation result contains any environment.* entry in violations, regardless of whether all transactional constraints (mandate.*, payment.*) also pass. Environment constraints gate execution; they are not co-equal with transactional constraints.

Per-member diagnostic output. Each failed environment.* constraint MUST produce its own entry in the violations list, naming the constraint type and the §4.2 step that failed. Verifiers MUST NOT collapse multiple environment.* failures into a single generic violation. This preserves the diagnostic signal needed for post-hoc analysis and dispute resolution.

Rationale. Each member of the family answers an independent question — is this market open? is this wallet still funded? Because the questions are independent, their answers compose as AND, not OR: a failure on any member removes the basis for execution. Collapsing per-member diagnostics would destroy the audit trail that makes the family load-bearing; preserving them makes every signed attestation recoverable from the validation output, and makes dispute resolution an application-layer concern with complete evidence rather than a debugging exercise.

Note on family coordination: Drafted as a standalone block adoptable verbatim in environment.market_state §5.5 with no changes. Same pattern as §4.7 — one family-wide question, one answer, two specs.


The three remaining follow-ups (JWKS caching/rotation, cross-chain temporal consistency, RFC 2119 audit) still read against v0.2 + this block. Happy to take them in any order you prefer; either venue works.

@LembaGang

Copy link
Copy Markdown

Caught up on 85cfaa0 this evening. The §5.5 core is right and I'd adopt it as drafted: conjunction semantics, no partial-fulfillment path, L3 gate, per-member diagnostic output. The passing-doesn't-rescue-failing framing is the load-bearing move and it lands cleanly. Your closing point on dispute resolution — that preserving per-member diagnostics makes disputes an application-layer concern with complete evidence rather than a debugging exercise — is the one I'd single out as quietly important: it's the clean separation between what the protocol owes (complete evidence) and what the application decides (what to do about it). Worth making that split explicit in normative text at some point, though not necessarily this revision.

One thing I'd add alongside your rationale rather than in place of it. Your "independent questions compose as AND" captures the semantic argument. The architectural argument reinforces it: conjunction also falls out of fail-closed posture directly. Any environment.* type whose failure mode is OR-tolerable is, by definition, outside the family's design charter — if a constraint's failure is survivable, it isn't gating execution, and if it isn't gating execution, it isn't in the family. This matters forward. When environment.regulatory_status or environment.counterparty_credit lands, conjunction isn't a design decision we re-litigate per type; it's a membership criterion. The semantic and architectural arguments are complementary and I think both belong in the rationale.

Two gaps I'd flag for a v0.3.1 pass:

Gap 1 — L3 gate timing vs. per-member diagnostic output. §5.5 mandates per-member diagnostic output for every failed environment.* constraint, but the L3 gate clause ("MUST NOT proceed to Layer 3 creation if the validation result contains any environment.* entry in violations") is compatible with short-circuit evaluation at first failure. These are in tension: short-circuit on first environment.* failure makes it impossible to produce per-member output for the remaining environment.* constraints. Proposed resolution: verifiers MUST evaluate all environment.* constraints to completion before refusing L3, so the violations list is complete. Transactional constraint evaluation after a confirmed environment.* failure stays implementation-defined (MAY evaluate for diagnostic completeness, MAY skip for efficiency) as long as L3 refusal is unambiguous. This also builds on §5.2's ordering requirement — environment before transactional stays, §5.5 adds the completeness rule on top.

Gap 2 — per-member disambiguation with same-type repeats. "Constraint type + §4.2 step" isn't sufficient to disambiguate when two constraints of the same type appear in the same mandate. My §4.5 multi-exchange example already has this case: two environment.market_state constraints, NYSE and LSE. If both fail, the current §5.5 text produces two violation entries that are indistinguishable on type+step alone. Proposed resolution: require each violation entry to carry the array index of the constraint in constraints[] as the primary machine identifier, plus a derived human-readable identifier from the constraint's distinguishing field (MIC for market_state, subject_wallet for wallet_state, whatever the analogous field is for future types). The array index is unambiguous; the derived identifier is what shows up in logs and dispute audits.

Happy to fold both into a v0.3.1 lift on PR #9 and have you mirror, or take them into your next commit on PR #22 — either venue works. Slight preference for mine since the §4.5 multi-exchange example is the concrete case Gap 2 resolves, but genuinely indifferent on mechanics.

On the remaining three items — JWKS caching, cross-chain temporal consistency, RFC 2119 audit — pick whichever is easiest for you to land next and I'll stage against it. I'm leaning into the 2119 audit on my side this weekend regardless since it's symmetric work and doesn't block on either of us.

@douglasborthwick-crypto

Copy link
Copy Markdown
Author

Read your 20:40 carefully. Adopting both gaps as drafted, and the architectural argument as a co-equal rationale — the membership-criterion framing is load-bearing for future environment.* types and keeps the family from accreting members whose failure modes don't gate execution. Worth making both semantic ("independent questions compose as AND") and architectural ("failure mode must be gating, or the type isn't in the family") explicit in the §5.5 rationale.

Gap 1 — L3 gate timing. Concur on the completeness rule. Proposed normative text, sitting above the per-member diagnostic paragraph:

Verifiers MUST evaluate every environment.* constraint in the mandate to completion before refusing Layer 3, even after the first failure has been observed. The violations list MUST contain one entry per failed environment.* constraint regardless of which member failed first. Short-circuit evaluation of environment.* constraints is non-conforming because it denies downstream consumers the per-member evidence the gate depends on. Transactional constraint evaluation (mandate.*, payment.*) after a confirmed environment.* failure remains implementation-defined (MAY evaluate for diagnostic completeness, MAY skip for efficiency) as long as L3 refusal is unambiguous.

Composes cleanly with §5.2's ordering rule — environment-before-transactional stays, completeness rule layers on top.

Gap 2 — per-member disambiguation. Concur, wallet_state analog:

  • Primary machine identifier: array index in constraints[].
  • Human-readable identifier (market_state): MIC — from signed attestation's mic field when present per §4.1, falling back to URL parse.
  • Human-readable identifier (wallet_state): subject_wallet (REQUIRED per §4 schema, always present).

Making distinguishing-field selection a per-type obligation (same shape as §4.6 max_attestation_age semantics) keeps §5.5 family-wide and puts implementation cost on the type author.

Venue. Your preference works. Take Gap 1 + Gap 2 into v0.3.1 on #9 — §4.5 multi-exchange is the clean driving case. I'll mirror on #22 once v0.3.1 lands, wallet_state examples in the same §5.5 slot.

Dispute resolution. Agree the split is worth normative text eventually — not blocking v0.3.1.

Next on #22. Picking JWKS caching and rotation next — wallet_state-specific, non-overlapping with your 2119 audit. Will stage the commit once v0.3.1 lands so we're not racing on §5.5 text.

@douglasborthwick-crypto douglasborthwick-crypto force-pushed the rfc-environment-wallet-state branch from eed3105 to f176515 Compare April 17, 2026 21:21
@douglasborthwick-crypto

Copy link
Copy Markdown
Author

Quick follow-up on sequencing. §6.8 JWKS Caching and Key Rotation staged as commit f176515 — second of the three remaining items.

On "not racing on §5.5 text": §6.8 is a new section (between §6.7 and §7), doesn't touch §5.5, and doesn't cite the Gap 1 completeness rule. Its per-constraint-scope rule stands on JWKS-specific security grounds. When Gap 1 mirror lands on §5.5 after your v0.3.1, the general completeness rule reinforces §6.8 without edits.

Sequencing holds:

The caching rules were drafted against live operational behaviour on the reference implementation side — Cache-Control: public, max-age=14400, must-revalidate, single stable kid — so the §6.8 normative text matches what verifiers will encounter in practice.

LembaGang added a commit to LembaGang/verifiable-intent that referenced this pull request Apr 18, 2026
Adds §5.5 Family Composition in response to the held-back follow-ups
from PR agent-intent#22 v0.2 review (conjunction semantics, L3 gate, per-member
diagnostic output). Co-drafted with Douglas Borthwick (InsumerAPI) over
PRs agent-intent#9 and agent-intent#22; mirrors PR agent-intent#22 §5.5 (commit 85cfaa0) with two
refinements agreed in PR agent-intent#22 discussion:

- Gap 1 (L3 gate timing): verifiers MUST evaluate every environment.*
  constraint to completion before refusing Layer 3; short-circuit
  evaluation is non-conforming. Composes with §5.2 ordering.

- Gap 2 (per-member disambiguation): every violation entry carries
  both an array-index machine identifier and a per-type human-readable
  identifier (MIC for market_state, subject_wallet for wallet_state).
  The §4.5 multi-exchange example (XNYS + XLON) is the driving case.

Rationale presents semantic ("independent questions compose as AND")
and architectural ("failure mode must be gating, or the type isn't in
the family") arguments as co-equal — conjunction as a family
membership criterion, not a per-type design decision. Load-bearing for
future environment.* types (regulatory_status, counterparty_credit).

Drafted as standalone block adoptable verbatim in environment.wallet_state
§5.5 with the per-type distinguishing-field row swapped. Same pattern
as §4.7 — one family-wide question, one answer, two specs.

No changes elsewhere in the spec; no verification algorithm, fail-closed,
or security-model changes; no Headless Oracle code changes required.

Co-Authored-By: Douglas Borthwick <douglasborthwick-crypto@users.noreply.github.com>
@LembaGang

Copy link
Copy Markdown

v0.3 of PR #9 landed — commit 7a8987c. §5.5 Family Composition sits between §5.4 and §6, five bold-label paragraphs: conjunction semantics, mixed pass/fail, L3 execution gate and completeness, per-member diagnostic output, rationale. Both gaps folded:

  • Gap 1 — the completeness rule lands verbatim from your proposed text, including "non-conforming" on short-circuit. Composes with §5.2 as you framed.

  • Gap 2 — per-member disambiguation with the per-type distinguishing-field obligation. MIC for market_state (from signed attestation's mic field per §4.1, falling back to URL parse); §4.5 multi-exchange (XNYS + XLON) cited as the driving case. Wallet_state row reserved for your mirror with subject_wallet as the analog — text already flags that explicitly.

Rationale presents semantic ("independent questions compose as AND") and architectural ("failure mode must be gating, or the type isn't in the family") as co-equal. Membership-criterion framing is in.

Coordination blockquote preserves the standalone-block-adoptable-verbatim pattern for your mirror onto §22 §5.5.

Thanks for the co-drafting pace this week. Your next move — JWKS caching on §6.8 as you staged, and the §5.5 mirror whenever it fits. I'll read §6.8 against v0.2 this weekend and raise any family-wide concerns in a separate comment; RFC 2119 audit continues in parallel on my side.

douglasborthwick-crypto added a commit to douglasborthwick-crypto/verifiable-intent that referenced this pull request Apr 18, 2026
… disambiguation (v0.3.1)

Mirrors PR agent-intent#9 v0.3 §5.5 Family Composition (commit 7a8987c,
environment-market-state) into environment-wallet-state.md. Two
refinements surfaced in PR agent-intent#22 discussion folded into §5.5.

Gap 1 (completeness rule): verifiers MUST evaluate every environment.*
constraint in the mandate to completion before refusing Layer 3 — even
after the first failure has been observed. Short-circuit evaluation of
environment.* constraints is non-conforming. Transactional-constraint
evaluation (mandate.*, payment.*) after a confirmed environment.*
failure remains implementation-defined. Composes with §5.2 ordering —
environment-before-transactional stays; completeness layers on top.

Gap 2 (per-member disambiguation): every violation entry MUST carry two
identifiers — the array index of the constraint in constraints[] as the
primary machine id, and a human-readable id derived from the
constraint's distinguishing field. Selection of the distinguishing
field is a per-type obligation analogous to per-type algorithm
declaration in §4.7. For environment.wallet_state the distinguishing
field is subject_wallet (REQUIRED per §4 schema, always present, no
fallback needed). Driving case: multiple wallet-state constraints in a
single mandate with different subject_wallet values (e.g., settlement
wallet + gas wallet).

Rationale now presents semantic and architectural arguments as
co-equal — conjunction as a family membership criterion, not a per-type
design decision. Any environment.* type whose failure mode is
OR-tolerable is outside the family's design charter.

No changes elsewhere in the spec; §4.1, §4.5, §4.7, §5.2, §6.*, §7.*
untouched. No InsumerAPI-side code changes required.

Co-Authored-By: LembaGang <127877551+LembaGang@users.noreply.github.com>
@douglasborthwick-crypto

Copy link
Copy Markdown
Author

§5.5 mirror shipped as 7848bc2 on rfc-environment-wallet-state, bumping the spec to v0.3.1-draft.

Gap 1 lifted verbatim — completeness rule, short-circuit non-conforming, transactional post-failure implementation-defined, composes with §5.2. Gap 2 adopted with subject_wallet as the environment.wallet_state distinguishing-field row (REQUIRED per §4 schema, always present, no fallback needed — simpler than the MIC case because the constraint-level field is always there). Driving case in the prose is multiple wallet-state constraints with different subject_wallet values (settlement wallet + gas wallet) — the same-type analog to your §4.5 XNYS+XLON example. Per-type swap on the cross-type mixed pass/fail example.

Handoff sequencing stays as you placed it — §6.8 on your weekend read, RFC 2119 audit on your side in parallel.

@LembaGang

Copy link
Copy Markdown

Douglas, caught up on your §5.5 mirror and §6.8 JWKS commits this afternoon.

The §5.5 mirror is clean. Subject_wallet as the wallet_state distinguishing-field with no fallback needed reads more cleanly than my MIC case precisely because the constraint-level field is always present. The settlement-wallet versus gas-wallet driving example is the right same-type analog to my §4.5 multi-exchange case. Family-wide §5.5 now lands identically across both specs.

On §6.8, the core is correct and I would adopt it. The kid-mismatch cache bust is the load-bearing primitive; tying trust-root semantics back to §6.3 on the fail-closed fetch rule is the right move; keeping the jti cache and JWKS cache independent in §6.2 closes a class of confusion before it starts; the "payment execution SHOULD NOT enable stale-cache fallback" carve-out is exactly the right nod to the strict-freshness deployment class.

One structural observation. Reading §6.8 against the family discipline we have established in §4.6, §4.7, and §5.5, each of those sections is family-wide by construction, adoptable verbatim in the sibling spec with per-type fields swapped. §6.8 reads the same way to me: every normative rule applies identically to any environment type that verifies via JWKS. The only wallet_state-specific mention is the example naming environment.wallet_state in the per-constraint-scope paragraph, which swaps cleanly to environment.market_state on my side. I do not have a §6.8 equivalent in the market_state spec yet, and market_state's JWKS pattern needs the same caching guidance or implementers will re-fetch per verification and create avoidable load.

Happy to lift §6.8 verbatim into the market_state spec as a v0.4 addition, same standalone-block pattern we used for §5.5. The only per-type swap is the example constraint-type name in the per-constraint-scope paragraph. Alternatively, if you would rather extend your §6.8 to explicitly name family-wide scope in the opening paragraph and I just reference it from the market_state side without duplicating the text, that also works, though my instinct is that duplication matches what we have done for §4.6, §4.7, and §5.5 and the family reads more symmetrically if each spec carries a full §6.8.

Three smaller items for a v0.3.2 pass or working-group review, none blocking.

One. Stale-cache fallback policy mechanism. The "deployment's security policy explicitly permits" line is correct but leaves the policy mechanism unspecified, whether mandate-level field, verifier config, or deployment config. A one-line note ("mechanism is implementation-defined but SHOULD be explicit and auditable") would close the ambiguity. A mandate-level stale_cache_fallback_permitted field with default false is the stricter version, if we want to take that path.

Two. Grace window discoverability. §6.8 correctly bounds the grace window by issuer-side quantities but does not specify how issuers communicate rotation start or grace-window end to downstream policy auditors. Could be a rotation_announcement JWKS metadata field, could be out-of-band. Polish-tier but worth raising before WG review.

Three. JWKS URL migration. §6.8 handles key rotation within a single JWKS URL. Issuer migration where trusted_jwks itself changes is currently a new-mandate event because trusted_jwks is part of the signed constraint. That is a defensible design choice, it keeps the trust-root binding rigid, but it is undocumented. Worth naming explicitly, either here or in §6.3, so implementers understand the migration path is not free.

Sequencing on my side. RFC 2119 audit continuing in parallel this weekend as flagged; any family-wide concerns from that on a separate comment. Cross-chain temporal consistency reads better against §6.8 plus the RFC 2119 pass than against v0.3.1 alone, so I would hold it for the round after v0.4.

@douglasborthwick-crypto

Copy link
Copy Markdown
Author

LembaGang —

Concur on verbatim duplication. Family discipline is the right read: §6.8 is family-wide in substance, and the only wallet_state-specific surface is the per-constraint-scope example naming environment.wallet_state. Lifting into market_state §6.8 with that one line swapped to environment.market_state holds the §4.6/§4.7/§5.5 pattern and keeps both specs self-contained for WG review. Asymmetric scope language at §6.8 after three prior symmetric passes would read as an inconsistency at review time.

On the three v0.3.2 items — all three are adoptable as family-wide with per-type localization. Proposed resolutions:

1. Stale-cache fallback mechanism. Taking the stricter path — schema addition, same shape as max_attestation_age. Proposed §4 schema row:

Field Type REQUIRED Description
stale_cache_fallback_permitted boolean Yes Whether verifiers MAY use an expired JWKS cache as a last-resort fallback when fresh JWKS fetch fails. Verifiers MUST apply a default of false when absent. Mandate issuers SHOULD include this field explicitly. Deployments with strict freshness requirements (e.g., payment execution) MUST NOT set this to true.

§6.8 companion paragraph (replaces the stale-cache sentences closing the "Fail-closed on fetch failure" paragraph, which are superseded by the field-level MUST NOT):

When stale_cache_fallback_permitted is true, verifiers MAY use an expired cache as a last-resort fallback on fresh-fetch failure; when false (the default), verifiers MUST produce a violation. For mandates where strict freshness is required (e.g., payment execution), the field MUST NOT be set to true.

Field-level shape matches max_attestation_age — consumer-policy constraint-level field, lifts verbatim into market_state.

2. Grace-window discoverability. SHOULD statement, no mandated mechanism. Proposed text, fitting between the issuer rotation responsibilities and fail-closed paragraphs of §6.8:

Issuers SHOULD publish rotation-start and grace-window-end timestamps through an auditable channel. The channel MAY be out-of-band (release notes, status page, signed rotation announcement) or in-band via a JWKS top-level metadata field (e.g., rotation_announcement: { rotation_started_at, previous_kid, new_kid, grace_window_end }). This specification does not mandate a mechanism; the SHOULD is on discoverability, not form. If the working group converges on a canonical in-band mechanism, a future revision can elevate it to REQUIRED.

Keeps the polish-tier posture you flagged. Adoptable verbatim across specs — nothing wallet-specific.

3. JWKS URL migration. Single paragraph, §6.3 rather than §6.8 — the rigidity is a property of the trust-root binding, not the caching layer. Proposed text for §6.3:

The trusted_jwks URL is a signed L2 constraint field. Issuers migrating to a new JWKS URL cannot be followed by existing mandates — migration is a new-mandate event. The migration path is: issuer publishes a new JWKS at the new URL; mandate issuers emit new mandates targeting the new URL; existing mandates with the old URL expire naturally via exp. This is a deliberate design choice that binds trust-root identity into the signed constraint rather than into a mutable issuer-side pointer. The cost is that URL migration is not free; the benefit is that the trust root cannot be silently relocated.

Adoptable verbatim; trust-root rigidity applies to any environment.* type with a signed JWKS URL.

Sequencing. Happy to fold all three into a single v0.3.2 commit on #22, with §6.8 duplication on your side landing as the market_state v0.4 addition. Cross-chain temporal consistency queued for the round after v0.4 as agreed — reads better against both specs once the stale-cache and migration text has stabilised. RFC 2119 audit continues on your side in parallel; I'll respond to family-wide findings when they land.

@LembaGang

Copy link
Copy Markdown

Douglas — concur across the board on the three resolutions. Specific reactions:

  1. stale_cache_fallback_permitted as a REQUIRED boolean with default=false is the right shape. Matching max_attestation_age's consumer-policy pattern keeps the constraint-level field family visible and puts the strict-freshness payment-execution deployment class into normative text rather than implementation-defined policy. The "MUST NOT set to true for strict freshness deployments" line closes what I flagged as the ambiguity in the §6.8 stale-cache paragraph.

  2. Grace-window SHOULD with the out-of-band or in-band optionality is better than mandating a mechanism. The rotation_announcement schema example you sketched is concrete enough to be useful without being normative — a working-group reference implementation can adopt it directly if the WG converges, and nobody is locked in if they don't. The elevation path ("future revision can elevate to REQUIRED") gives the WG a clear next step without pre-judging it.

  3. JWKS URL migration at §6.3 rather than §6.8 is the right placement — the rigidity is a trust-root property, not a caching property. The "deliberate design choice" framing with explicit cost/benefit captures what was previously implicit. Worth the paragraph.

Two things to raise before we pin v0.4 shape.

First, version number sequencing. I pushed a v0.3.2-draft on PR #9 a few minutes ago — commit 67a5adb, an RFC 2119 audit pass. Two local fixes: max_attestation_age strictness (closes the v0.2 REQUIRED+default contradiction — strict REQUIRED, no default, missing field is malformed and verifiers MUST reject) and §6.5 Constraint Stripping normative hardening (previously zero normative keywords in a security-considerations section). Both HO-local; no family-wide surface touched. So v0.3.2 is taken on the market_state side for a P1 patch.

My suggestion: let's converge your three resolutions plus the §6.8 duplication into v0.4 on both specs, landing identically. §6.8 verbatim + new stale_cache_fallback_permitted schema field + §6.8 grace-window SHOULD paragraph + §6.3 URL migration paragraph. That gives v0.4 substantive release shape rather than splitting across v0.3.2 and v0.4.

Second, a family-wide finding from the v0.3.2 audit that I should flag rather than bury: the max_attestation_age REQUIRED+default-60 contradiction exists symmetrically on PR #22 — same elevation to REQUIRED in v0.2 with "normative default of 60 seconds" language, same silent-restoration of the TOCTOU surface that §4.6 is designed to close. I fixed it on PR #9 tonight. Your side has the same logical gap. Two paths forward: (a) you lift the strictness pass onto PR #22 as a separate v0.3.1.1 or similar patch before the v0.4 round, symmetric to what I just shipped; or (b) we fold the strictness pass into v0.4 alongside your three items, so v0.4 on both specs resolves max_attestation_age contradiction plus stale_cache_fallback_permitted plus grace window plus URL migration plus §6.8 in one coordinated release. My preference is (b) — cleaner versioning and the family charter in §2.3/§4.6 stays truthful without a temporary divergence window. Your call on venue mechanics.

Sequencing on my side for v0.4: I will lift §6.8 onto PR #9 with the one-line per-type swap on the per-constraint-scope paragraph, plus whatever localization is needed on the stale_cache_fallback_permitted examples. Same lockstep pattern as §5.5. RFC 2119 full findings summary coming in a separate comment on PR #9 — preview: beyond the max_attestation_age P1 (fixed) and §6.5 gap (fixed), the third finding is SHALL/MUST normalization (both specs use SHALL a handful of times; MUST is more conventional — one-line find-and-replace). Everything else was market_state-local.

@douglasborthwick-crypto

Copy link
Copy Markdown
Author

LembaGang —

Concur on (b). v0.3.1.1 would read as a procedural patch rather than a substantive release — landing audit-parity + family-wide additions together keeps the §2.3/§4.6 charter coherent on both sides.

Audit-parity drafted locally against 67a5adbmax_attestation_age strictness across all five sites (§4 schema, §4 Field Constraints, §4.2 Step 1, §7.6 JS, §7.7 Python) and §6.5 stripping with your two MUST/MUST NOT sentences lifted verbatim. Reframing the changelog entry from v0.3.2 to v0.4 and rolling in the three JWKS items + §6.8 duplication is a one-pass adjustment — no rework.

One thing to raise before v0.4 shape pins. The stale_cache_fallback_permitted row from my 17:42 has the same REQUIRED+default pattern you just P1'd — "REQUIRED: Yes" + "Verifiers MUST apply a default of false when absent." Security direction is opposite (fail-secure rather than fail-open), so the operational risk is lower than the max_attestation_age case, but the logical shape is identical and a WG reviewer cross-checking against your v0.3.2 audit will catch it.

Two paths, your call:

(i) OPTIONAL with default=false — matches the "missing = safe default" semantic. Stricter deployment rule ("payment execution MUST NOT set to true") lands as field guidance, not presence guidance.

(ii) REQUIRED, no default, missing=malformed — full parity with the max_attestation_age pattern you just shipped. Forces every mandate issuer to declare a cache-fallback policy explicitly.

My lean is (i) — the defaulted value is fail-secure, and forcing explicit declaration on every mandate doesn't buy security surface the way it does for max_attestation_age. But (ii) has the family-consistency argument. Happy either way; flagging before it bakes.

Sequencing on my side:

Once your preference on (i)/(ii) is down and the SHALL→MUST findings are out, v0.4 on PR #22 goes up — single commit, parallel to whatever shape lands on PR #9.

@LembaGang

Copy link
Copy Markdown

Douglas — (b) locked. Audit-parity + stale_cache_fallback_permitted + grace window + URL migration + §6.8 duplication as a single v0.4 release on both specs. The v0.3.1.1 route would read as a procedural patch where we want a substantive release; rolling it all into one keeps the §2.3/§4.6 charter coherent through the transition and gives v0.4 the shape a WG reviewer or acquirer engineer sees as a real milestone rather than a sequence of fix-ups.

On the (i) vs (ii) question — I'm landing on (i), OPTIONAL with default=false, with reasoning you should stress-test before we bake it.

The v0.3.2 audit closed a REQUIRED+default contradiction specifically — a field can't be both REQUIRED (missing = malformed) and carry deterministic absent-case behaviour. stale_cache_fallback_permitted doesn't have to inherit the REQUIRED framing; OPTIONAL with a fail-secure default of false is a different schema shape that doesn't recreate the contradiction. The security posture is independent of the REQUIRED/OPTIONAL choice — fail-secure-by-default covers the "implementer forgot the field" case whether the field is formally REQUIRED-rejecting-when-absent or OPTIONAL-applying-default-when-absent.

Two consistency notes against the v0.3.2 audit pattern:

  • max_attestation_age was REQUIRED because any nontrivial default is unsafe in some deployment class — the safe value depends on the deployment's TOCTOU tolerance, which the spec cannot guess.
  • stale_cache_fallback_permitted is OPTIONAL because a single default (false) is correct for almost all deployments, and the minority of deployments that want stale-cache fallback declare true explicitly.

Open question back to you: is there a scenario where stale_cache_fallback_permitted default-false is actually fail-open that I'm missing? The case I can construct is "deployment wants strict-freshness behavior, mandate-level MUST NOT catches it" — which is already your 17:42 text. If you see a surface I haven't considered, now's the time to raise it before the v0.4 commit bakes.

Sequencing on my side: SHALL/MUST normalization isn't a finding. Post-audit verification showed all SHALL references in the market_state spec are on line 66 inside the RFC 2119 Notational Conventions boilerplate — zero substantive usage elsewhere. Full findings summary on PR 9 landed with the correction. No normalization work to fold into v0.4.

§6.8 duplication onto PR 9 with the per-type example swap reads clean. I'll lift it once your v0.4 commit lands, same lockstep pattern as §5.5.

@douglasborthwick-crypto

Copy link
Copy Markdown
Author

LembaGang —

Concur on (b) + (i). The REQUIRED-vs-OPTIONAL distinction you drew — REQUIRED because no nontrivial default is safe across deployment classes (max_attestation_age), OPTIONAL because a single default is correct for almost all deployments (stale_cache_fallback_permitted) — reads as the right framing for the family going forward. Narrows the v0.3.2 contradiction to its specific cause (REQUIRED + deterministic absent-case behaviour) rather than generalizing to "no defaults ever."

On the stress-test question: I can't construct a fail-open scenario under (i) that you're missing. Three surfaces I walked:

  1. Missing field → default-false applies → verifier MUST produce violation on fresh-fetch failure. Fail-secure.
  2. Stripped field → L2 signature no longer validates over the full constraint list → §6.5 (v0.3.2) requires verifier to reject. Detection, not silent downgrade.
  3. Non-boolean value present (e.g., string "false", null, or a number) → default behaviour wouldn't apply because the field is present; if the spec doesn't require strict boolean typing, a non-boolean value is ambiguous and an implementer might coerce it. Small hygiene fix that mirrors the max_attestation_age Field Constraints bullet: "If present, MUST be boolean; non-boolean values MUST be rejected as malformed per §4.2 Step 1." Closes the ambiguity without adding semantic surface.

Mandate-level MUST NOT for payment-execution is already in my 17:42 text and handles the explicit-true-with-strict-freshness case.

Unless you see a different surface, I'll bake (i) with the boolean-type clause into the v0.4 schema row alongside the two JWKS paragraphs from my 17:42 and the audit-parity lifts from 57fd7b6.

Sequencing confirmed: v0.4 commit on #22 next, §6.8 lift onto #9 after it lands. Same lockstep as §5.5.

@LembaGang

Copy link
Copy Markdown

Douglas — (i) with the boolean-type clause confirmed. I walked surfaces 4-8 from your three baseline and can't construct an additional fail-open path: nested/malformed JSON, loose-typed coercion of boolean-like strings, and attacker-set-to-true are either caught by your proposed clause or outside the field's scope (covered by the payment-execution MUST NOT or the mandate-issuer trust model).

Bake (i) + "If present, MUST be boolean; non-boolean values MUST be rejected as malformed per §4.2 Step 1" as proposed. The clause reads as a parallel-construction match to the max_attestation_age Field Constraints bullet from v0.3.2, which continues the family hygiene at the bullet level alongside the section-level lockstep we have on §4.6/§4.7/§5.5/§6.8.

Sequencing confirmed: your v0.4 commit on #22 next, §6.8 lift onto #9 after it lands.

One small thanks: the narrowing of the v0.3.2 rule to its specific cause (REQUIRED + deterministic absent-case behaviour) rather than "no defaults ever" is the framing I want going forward for future environment.* consumer-policy fields. Worth calling out that you landed on it cleanly.

douglasborthwick-crypto added a commit to douglasborthwick-crypto/verifiable-intent that referenced this pull request Apr 18, 2026
Coordinated v0.4 release with PR agent-intent#9 environment.market_state as a
single-commit-on-both-specs bundle per LembaGang's (b) proposal
accepted in PR agent-intent#22 comment 4274334595 and locked at comment 4274435668.
LembaGang lifts §6.8 onto PR agent-intent#9 v0.4 after this lands, same lockstep
pattern as §5.5.

Audit-parity port from PR agent-intent#9 v0.3.2 (commit 57fd7b6, LembaGang):

(1) max_attestation_age strictness — removed absent-case default of 300
    seconds from:
    - §4 schema row: "default of 300" + "SHOULD always include"
      softener replaced with explicit MUST-include + MUST-reject-if-
      missing.
    - §4 Field Constraints bullet: "when absent... default of 300"
      replaced with malformed-rejection + no-default declaration +
      §4.6 security rationale.
    - §4.2 pseudocode Step 1: added absent-check before range check.
    - §7.6 JS reference: removed destructuring default; added
      undefined-check throw.
    - §7.7 Python reference: removed .get() default; added membership-
      check + ValueError.

    Missing max_attestation_age is now uniformly malformed; verifiers
    MUST reject per §4.2 Step 1. Closes the v0.2 REQUIRED-elevation-
    with-retained-default contradiction.

(2) §6.5 Constraint Stripping — added normative sentences requiring
    verifiers to reject mandates whose Layer 2 signature does not
    validate over the full constraint list, and prohibiting acceptance
    of subset-signed mandates. Closes the zero-normative-keyword gap
    identified by LembaGang's RFC 2119 audit.

Three consumer-policy additions (Doug's Apr 18 17:42 proposal comment
4274241447, LembaGang-approved in comment 4274435668):

(3) stale_cache_fallback_permitted OPTIONAL boolean field (default
    false):
    - §4 schema row added (OPTIONAL per LembaGang (i) at 4274435668;
      default-false; payment-execution MUST NOT set true).
    - §4 Field Constraints bullet with boolean-type hygiene clause:
      "if present, MUST be a strict boolean. Non-boolean values
      (including string "false", null, or numeric) MUST be rejected
      as malformed per §4.2 Step 1."
    - §4.2 pseudocode Step 1 type-check.
    - §6.8 "Fail-closed on fetch failure" paragraph: stale-cache
      sentences replaced with field-driven text (MAY use expired cache
      when true, MUST produce violation when false/absent, payment-
      execution MUST NOT set true).

    Shape follows the v0.3.2 rule-narrowing: REQUIRED remains the right
    pattern where no nontrivial default is safe across deployment
    classes (max_attestation_age); OPTIONAL-with-default is the right
    pattern where a single default is correct for almost all
    deployments (stale_cache_fallback_permitted). Parallel-construction
    Field Constraints bullet matches the max_attestation_age pattern.

(4) §6.8 grace-window discoverability: issuers SHOULD publish
    rotation-start and grace-window-end timestamps through an auditable
    channel. Channel MAY be out-of-band (release notes, status page,
    signed rotation announcement) or in-band via a JWKS top-level
    metadata field (e.g., rotation_announcement with
    rotation_started_at / previous_kid / new_kid / grace_window_end).
    SHOULD is on discoverability, not form. Future revision may elevate
    to REQUIRED if the WG converges on a canonical in-band mechanism.

(5) §6.3 JWKS URL migration paragraph: trusted_jwks URL change is a
    new-mandate event by design. Migration path: issuer publishes a
    new JWKS at the new URL; mandate issuers emit new mandates
    targeting the new URL; existing mandates expire naturally via
    exp. Deliberate cost/benefit: trust root cannot be silently
    relocated, at the cost of non-free URL migration.

(6) SHALL→MUST normalization NOT NEEDED: post-audit verification on
    both specs shows all SHALL references sit in the RFC 2119
    Notational Conventions boilerplate (line 67 on agent-intent#22, line 66 on
    agent-intent#9); zero substantive usage elsewhere. LembaGang's P3 finding
    withdrawn on PR agent-intent#9, symmetric on agent-intent#22.

§9 changelog: v0.4-draft row added above v0.3.1-draft.

No architectural changes. No family-wide changes. No InsumerAPI-side
code changes required. Co-drafted with LembaGang (Headless Oracle)
over PRs agent-intent#9 and agent-intent#22.

Co-Authored-By: LembaGang <127877551+LembaGang@users.noreply.github.com>
@douglasborthwick-crypto

Copy link
Copy Markdown
Author

LembaGang —

v0.4 shipped on #22 as bb7af90. Six items bundled per our coordinated plan:

  1. max_attestation_age strictness — Path b strict-REQUIRED applied across all five sites (§4 schema row, §4 Field Constraints, §4.2 pseudocode Step 1, §7.6 JS, §7.7 Python), matching your 57fd7b6 pattern with the 300 → no-default localized.
  2. §6.5 Constraint Stripping — two MUST / MUST NOT sentences lifted verbatim from 57fd7b6.
  3. stale_cache_fallback_permitted — new OPTIONAL boolean field, default-false, with the boolean-type hygiene bullet you approved at 4274435668. §4 schema row + Field Constraints bullet + §4.2 Step 1 type-check + §6.8 "Fail-closed on fetch failure" paragraph companion text (replaces the prior stale-cache sentences; payment-execution MUST NOT remains).
  4. §6.8 grace-window discoverability — SHOULD paragraph added between issuer-rotation-responsibilities and Fail-closed paragraphs; out-of-band OR in-band rotation_announcement metadata as drafted; SHOULD on discoverability, not form.
  5. §6.3 JWKS URL migration — paragraph added at end of §6.3; new-mandate-event framing + deliberate cost/benefit on trust-root rigidity.
  6. SHALL→MUST normalization — not applied; all SHALL on RFC: environment.wallet_state — sibling constraint for on-chain wallet state #22 is in the RFC 2119 Notational Conventions boilerplate at L67, zero substantive usage (symmetric to your P3 withdrawal on RFC: Add External State Attestation constraint type for autonomous ex…RFC: External State Attestation — Environmental Verification Constraint for Autonomous Execution #9).

Working-tree diff: +57 / -13 across spec/environment-wallet-state.md only. No reference-implementation behaviour changes beyond the two undefined/membership checks; no InsumerAPI code impact.

Handoff: §6.8 lift onto #9 is yours next, same lockstep as §5.5. Ping me if anything on the new §6.8 Fail-closed wording or the stale_cache_fallback_permitted shape needs tightening before your lift.

LembaGang added a commit to LembaGang/verifiable-intent that referenced this pull request Apr 18, 2026
…back_permitted

Lifts the family-wide additions shipped by Douglas in PR agent-intent#22 bb7af90 with
terminology adaptation for market_state's key-discovery architecture.

Additions:
- New §6.8 Key Registry Caching and Key Rotation: lifted from bb7af90's
  §6.8 JWKS Caching and Key Rotation with systematic terminology swaps
  (JWKS → RFC 8615 key registry, kid → key_id, trusted_jwks → issuer-
  derived oracle key registry URL). All MUST/SHOULD/MAY keywords and
  paragraph ordering preserved verbatim. Includes grace-window SHOULD
  paragraph with rotation_announcement metadata example adapted to
  market_state's key registry shape.
- stale_cache_fallback_permitted OPTIONAL boolean field (§4 schema row,
  §4 Field Constraints bullet with "If present MUST be boolean" hygiene
  clause per Douglas's v0.4 addition, §4.2 Step 1 type-check, §6.8
  companion paragraph). Default false; payment-execution MUST NOT set
  true.

Intentional asymmetry — not lifted:
- §6.3 JWKS URL migration paragraph from bb7af90. wallet_state's
  trusted_jwks is a signed L2 constraint field (user-signed); market_
  state's registry URL is derived from the oracle's issuer field
  (oracle-signed). The underlying property Douglas's paragraph addresses
  — trust-root URL as rigid mandate binding — does not exist in
  market_state. This asymmetry is pre-existing and already documented
  in §6.3's JWKS/RFC-8615 coexistence paragraph. The coordination work
  this week treated §6.3 as family-symmetric; the spec itself says
  otherwise. Formalizing trust-root-binding as an explicit family-
  charter dimension queued for v0.5.

Scope of family-wide claims:
- §4.6 family-wide framing continues to cover max_attestation_age only.
- stale_cache_fallback_permitted is scoped per-type with parallel
  semantics to PR agent-intent#22's version. Field governs stale-cache fallback on
  the trust-root mechanism the constraint uses; the mechanism differs
  between types, so the field's operational scope is per-type.

Changelog: 0.4-draft row added above 0.3.2-draft.

Co-Authored-By: Douglas Borthwick <256362537+douglasborthwick-crypto@users.noreply.github.com>
@LembaGang

Copy link
Copy Markdown

Douglas — v0.4 on PR #9 shipped as 53ea1c6. Lifts §6.8 with RFC 8615 key registry terminology, stale_cache_fallback_permitted as OPTIONAL boolean with the boolean-type hygiene clause, grace-window SHOULD paragraph.

Two items to flag from the lift.

First, §6.3's JWKS URL migration paragraph does not port. PR #9's §6.3 already documents the asymmetry in its JWKS/RFC-8615 coexistence paragraph: wallet_state's trusted_jwks is a signed L2 constraint field (user-signed), market_state's registry URL is derived from the oracle's issuer field (oracle-signed). The trust-root-rigidity property your paragraph asserts exists only in wallet_state's threat model. Not lifted, flagged in the v0.4 changelog. The coordination work this week treated §6.3 as family-symmetric; the spec body had already acknowledged it wasn't. Worth naming so the asymmetry doesn't resurface in v0.5.

Second, surfaced during the v0.4 lift review: the scoping of stale_cache_fallback_permitted is provenance-only on both our specs. §4.6 says max_attestation_age is family-wide. stale_cache_fallback_permitted is per-type (trust-root-mechanism-bound, differs between JWKS and key registry). But neither of our specs' normative bodies expresses this distinction — only the v0.4 changelog entries do. An agent composing a mandate that mixes environment.market_state and environment.wallet_state has no machine-discoverable way to know which shared field names share semantics.

This is the v0.5 work queued in the v0.4 changelog, and I want to flag it as time-sensitive. Once a third implementer arrives, they'll read §4.6's family-wide framing and reasonably bake in a family-wide assumption for every field named identically across both specs. That becomes hard to walk back.

Proposal for v0.5 scope: formalize trust-root-binding as an explicit family-charter dimension in §4.6 (or a new §4.8). Each field declares its scope: family-wide-trust-root-agnostic, or per-type-trust-root-mechanism-bound. max_attestation_age is the first category; stale_cache_fallback_permitted is the second; future fields declare their category at introduction.

Happy to draft §4.8 on PR #9 as a standalone block adoptable verbatim on PR #22 — same pattern we've used for every shared-structure section. Could land next weekend.

Otherwise v0.4 is in lockstep on both sides. The boolean-type hygiene clause you proposed ended up being the most load-bearing precision in the family-wide work this week.

@douglasborthwick-crypto

Copy link
Copy Markdown
Author

Michael —

Accepting the v0.5 scope and §4.8 drafting on PR #9. The §6.3 framing miss is on me; better to name it now than let it resurface in outside code. The stale_cache_fallback_permitted scoping gap is the more consequential catch — a third implementer reading §4.6 will reasonably generalize family-wide to every shared field name, and that assumption is hard to walk back.

One pin before you draft: §4.6 vs new §4.8. §4.6 is currently scoped to max_attestation_age specifically (per your 53ea1c6 commit note — "§4.6 family-wide framing continues to cover max_attestation_age only"). Promoting it into a general family-charter section would re-scope existing normative text; adding §4.8 as a standalone charter section leaves §4.6 intact and makes the discipline visible at TOC level. Slight lean toward new §4.8 for that second reason, but genuinely indifferent on mechanics — your call on where the charter reads cleanest.

Otherwise lockstep. Will port verbatim when you land. And glad the boolean clause earned its keep.

@LembaGang

Copy link
Copy Markdown

Douglas —

v0.5-draft on PR #9 shipped as commit 1ab7a83. §4.8 Field Scope Declaration landed between §4.7 and §5 as the standalone-block we agreed.

Summary of what §4.8 does:

Declares two scope categories for environment.* fields:

  • family-wide-trust-root-agnostic — semantics identical across types, independent of trust-root mechanism. max_attestation_age (§4.6) is the current instance.
  • per-type-trust-root-mechanism-bound — operational semantics depend on the type's trust-root mechanism (JWKS for wallet_state, RFC 8615 key registry for market_state). stale_cache_fallback_permitted (§6.8) is the current instance.

Forward rule: new environment.* fields MUST declare scope category at introduction. New categories beyond the two currently recognised are working-group revisions.

§4.8 preserves §4.6 normative text unchanged — it formalises the scope distinction §4.6 and §4.7 already imply in their specific domains, rather than re-scoping §4.6's existing text. Cross-references §4.6 and §4.7 explicitly.

One housekeeping note folded into the same commit: document header bumped from 0.3-draft to 0.5-draft. The v0.4 commit (53ea1c6) shipped with the header still at 0.3-draft — the body and changelog were correct, only the top-of-file version marker lagged.


On the mirror onto PR #22 §4.8. Pre-walked your current schema fields against the two-category taxonomy. Three of them land cleanly, three land cleanly with a note, and two surface a taxonomy gap worth flagging before you commit.

Clean per-type-trust-root-mechanism-bound:

  • trusted_jwks — the canonical trust-root URL for wallet_state; the whole concept of "trust root URL as signed L2 field" is JWKS-specific (market_state derives its registry URL from the attestation issuer, not a signed constraint field).
  • expected_kid — JWT kid header semantics; market_state uses oracle_public_key_id against a different key-identifier scheme in its RFC 8615 registry.
  • expected_issuer — JWT iss claim semantics; no directly equivalent constraint-level field on market_state since the attestation's issuer serves that role implicitly.

Clean family-wide-trust-root-agnostic:

  • attestation_url — HTTPS endpoint for signed attestation fetch. Family-wide at the level §4.8 operates on (the concept of the field); the HTTP method and body shape are per-type but that's implementation-bound, not trust-root-bound.
  • max_attestation_age — already declared family-wide in the market_state §4.8, semantics identical on your side.

Clean per-type-trust-root-mechanism-bound with a flag for v0.6+:

  • subject_wallet — today clearly per-type (JWT sub claim semantics, JWKS/JWS-specific). But your §8 Q5 open question proposes a family-wide subject-binding unification. If the WG accepts the §8 Q5 proposal in a future revision, subject_wallet would migrate from per-type to family-wide alongside a renamed market_state subject field. The v0.5 §4.8 framework supports that migration without revision — the rule-for-future-fields clause anticipates scope changes across versions.
  • stale_cache_fallback_permitted — already declared per-type; your side is the JWKS cache rather than the RFC 8615 registry cache but otherwise identical.

Two fields that surface a taxonomy gap:

  • required_condition_hashes — per-type on your side, no market_state equivalent. But the binding isn't to a trust-root mechanism; it's to wallet_state's evaluation primitive (condition hashes as the binding format). A boolean-status expected_status on market_state is the same structural role — per-type evaluation primitive, not per-type trust-root binding.
  • attestation_request_body — per-type OPTIONAL on your side, no market_state equivalent. Same structural role as above — per-type wire-protocol shape, not per-type trust-root mechanism.

The current §4.8 taxonomy has one "per-type" bucket labelled "trust-root-mechanism-bound." These two fields are clearly per-type but not because of trust-root mechanism; they're per-type because of evaluation semantics and wire protocol.

Three options for handling:

  1. Broaden the per-type category name to something like per-type-implementation-specific or per-type-attestation-mechanism-bound. Covers trust-root, evaluation, and wire-protocol bindings under one umbrella. Lightest touch.

  2. Split into distinct categories — add something like per-type-evaluation-specific for condition hashes and request bodies. Crisper semantics, more surface area.

  3. Defer to v0.6. For v0.5, place required_condition_hashes and attestation_request_body under the existing per-type category with a one-line note that the binding is evaluation/protocol rather than trust-root. Flag for taxonomy refinement next revision. Minimum-viable, preserves current framework.

My lean is (3) — lightest-touch commit for you today, gives the working group a named gap to discuss rather than pre-committing to a taxonomy fix. But the choice is yours since your side surfaces the gap. Happy to ship market_state's §4.8 taxonomy update in lockstep once you've committed to a direction.

Cross-chain temporal consistency and RFC 2119 audit still queued for whichever of us picks them up next; v0.5 §4.8 doesn't touch either.

LembaGang added a commit to LembaGang/verifiable-intent that referenced this pull request May 6, 2026
… + per-type)

Mirrors PR agent-intent#22 v0.6.5-draft commit 66185a1 (Douglas Borthwick, InsumerAPI).

Adds family-wide algorithm-deprecation prose to §4.7 mirroring
draft-borthwick-msebenzi-environment-state-00 v0.2-draft §4.3 family-wide
SHOULD ("Type specification authors SHOULD specify, in the type's
specification, a deprecation mechanism for the type's MUST-implement
algorithm before that algorithm is needed").

Adds per-type deprecation mechanism for environment.market_state:
conditions (NIST / IRTF CFRG / RFC 8032 / RFC 8725 update or cryptographic
break), timeline (>=12-month verifier-migration window from minor-version
revision publication; parallel verification during window; rejection after
window end), backward compatibility (mandate-issuer migration on key-
registry readiness; verifier detection via RFC 8615 well-known key-set
inspection at {issuer}/.well-known/oracle-keys.json).

Updates §4.7 PR agent-intent#22 coordination Note to reflect the family-wide algorithm-
deprecation discipline as co-equal with the agility framework, extension-set
model, and fail-closed-negotiation requirement.

Family-wide prose (algorithm-agnostic policy paragraph, single-algorithm
lock-in paragraph, family-wide deprecation paragraph) byte-identical to
PR agent-intent#22 §4.7.

Co-Authored-By: douglasborthwick-crypto <256362537+douglasborthwick-crypto@users.noreply.github.com>
douglasborthwick-crypto and others added 16 commits May 12, 2026 16:29
…t state

Proposes environment.wallet_state as a second constraint type in the
environment.* namespace (following environment.market_state, PR agent-intent#9).

Requires agents to obtain an ES256 JWT attestation binding a signed
boolean verdict to a specific source wallet and condition hash before
L3 execution. Fail-closed, structurally identical to market_state.

Also answers PR agent-intent#9 §8 Q2 (trusted_issuers) by binding trust to the
JWKS signing key rather than the attestation_url.

Reference implementation: InsumerAPI (https://api.insumermodel.com),
verified live 2026-04-15.
…ithm agility

Addresses LembaGang review (comment 4259989585) with three structural changes:

1. Provider neutrality: §4.1 restructured as abstract attestation interface.
   7 REQUIRED JWT claims (iss, sub, jti, iat, exp, pass, conditionHash) define
   the normative contract. results/blockNumber/blockTimestamp moved to OPTIONAL.
   Condition hash canonicalization moved to §7.2 as issuer-specific detail.
   A second conformant implementation needs only the core claims and a JWKS.

2. Attestation freshness: max_age_seconds renamed to max_attestation_age,
   elevated to REQUIRED with normative default of 300. New §4.6 documents
   TOCTOU rationale (Mango/Balancer oracle exploit class) and family-wide
   semantics. PR agent-intent#9 invited to adopt identical field and semantics.

3. Algorithm agility: New §4.7 resolves former Q1. Family-level agility per
   RFC 8725 §3.1, per-type MUST-implement (ES256 for wallet_state, Ed25519
   for market_state), SHOULD/MAY extension sets. Drafted as standalone block
   for verbatim adoption in PR agent-intent#9.

§6.1 and §6.6 genericized (InsumerAPI-specific URLs and canonicalization
detail consolidated in §7). §7 restructured into subsections (7.1–7.7).

No changes to the verification algorithm logic or security model.
Zero InsumerAPI code changes required.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Answers the first of the four held-back follow-ups from PR agent-intent#9 v0.2
review (composition semantics on mixed pass/fail). New §5.5 in
environment-wallet-state.md between §5.4 Output Fields and §6 Security
Considerations:

- Conjunction semantics (family gate = AND across all environment.*)
- Named answer for the mixed pass/fail case (market_state passes,
  wallet_state fails -> family fails; no partial-fulfillment path)
- L3 execution gate as explicit normative rule (MUST NOT proceed to
  L3 if any environment.* entry in violations, regardless of
  transactional constraint outcome)
- Per-member diagnostic output (each failed environment.* produces
  its own violations entry; verifiers MUST NOT collapse)

§5.2 and all other sections unchanged. Drafted as standalone block
adoptable verbatim in environment.market_state §5.5 with no changes —
same pattern as §4.7.

Co-Authored-By: LembaGang <127877551+LembaGang@users.noreply.github.com>
Answers the second of the four held-back follow-ups from PR agent-intent#9 v0.2
review (JWKS caching/rotation — scoped as wallet_state-specific since
environment.market_state uses an RFC 8615 key registry rather than a
JWKS URI). New §6.8 in environment-wallet-state.md between §6.7 Time
Synchronisation and §7 Reference Implementation:

- Caching permissibility: verifiers MAY cache, SHOULD respect the
  issuer's Cache-Control directive when present; TTL is
  implementation-defined when Cache-Control is absent
- Kid-mismatch as cache bust: unrecognised kid MUST trigger fresh
  JWKS fetch before rejection, so rotated keys are discoverable
  without waiting for TTL
- Issuer rotation: both old and new keys published simultaneously
  during a grace window exceeding both max attestation lifetime and
  verifier cache TTL
- Fail-closed on fetch failure: no fallback to hard-coded keys;
  stale-cache fallback permitted only when deployment policy allows
- Per-constraint scope: JWKS fetch failure on one wallet_state
  constraint MUST NOT short-circuit other environment.* constraints;
  each produces its own violation entry independently
- Interaction with §6.2 replay cache: independent, no cross-dependency

No changes to §5.5 text in this commit — Gap 1 (completeness rule) +
Gap 2 (array index + subject_wallet identifier) mirror lands in a
subsequent commit after PR agent-intent#9 v0.3.1 ships, per sibling-spec venue
agreement.

Drafted as standalone block; agent-intent#9 MAY adopt symmetric JWKS-style caching
as optional hardening per its §6.3 note.
… disambiguation (v0.3.1)

Mirrors PR agent-intent#9 v0.3 §5.5 Family Composition (commit 7a8987c,
environment-market-state) into environment-wallet-state.md. Two
refinements surfaced in PR agent-intent#22 discussion folded into §5.5.

Gap 1 (completeness rule): verifiers MUST evaluate every environment.*
constraint in the mandate to completion before refusing Layer 3 — even
after the first failure has been observed. Short-circuit evaluation of
environment.* constraints is non-conforming. Transactional-constraint
evaluation (mandate.*, payment.*) after a confirmed environment.*
failure remains implementation-defined. Composes with §5.2 ordering —
environment-before-transactional stays; completeness layers on top.

Gap 2 (per-member disambiguation): every violation entry MUST carry two
identifiers — the array index of the constraint in constraints[] as the
primary machine id, and a human-readable id derived from the
constraint's distinguishing field. Selection of the distinguishing
field is a per-type obligation analogous to per-type algorithm
declaration in §4.7. For environment.wallet_state the distinguishing
field is subject_wallet (REQUIRED per §4 schema, always present, no
fallback needed). Driving case: multiple wallet-state constraints in a
single mandate with different subject_wallet values (e.g., settlement
wallet + gas wallet).

Rationale now presents semantic and architectural arguments as
co-equal — conjunction as a family membership criterion, not a per-type
design decision. Any environment.* type whose failure mode is
OR-tolerable is outside the family's design charter.

No changes elsewhere in the spec; §4.1, §4.5, §4.7, §5.2, §6.*, §7.*
untouched. No InsumerAPI-side code changes required.

Co-Authored-By: LembaGang <127877551+LembaGang@users.noreply.github.com>
Coordinated v0.4 release with PR agent-intent#9 environment.market_state as a
single-commit-on-both-specs bundle per LembaGang's (b) proposal
accepted in PR agent-intent#22 comment 4274334595 and locked at comment 4274435668.
LembaGang lifts §6.8 onto PR agent-intent#9 v0.4 after this lands, same lockstep
pattern as §5.5.

Audit-parity port from PR agent-intent#9 v0.3.2 (commit 57fd7b6, LembaGang):

(1) max_attestation_age strictness — removed absent-case default of 300
    seconds from:
    - §4 schema row: "default of 300" + "SHOULD always include"
      softener replaced with explicit MUST-include + MUST-reject-if-
      missing.
    - §4 Field Constraints bullet: "when absent... default of 300"
      replaced with malformed-rejection + no-default declaration +
      §4.6 security rationale.
    - §4.2 pseudocode Step 1: added absent-check before range check.
    - §7.6 JS reference: removed destructuring default; added
      undefined-check throw.
    - §7.7 Python reference: removed .get() default; added membership-
      check + ValueError.

    Missing max_attestation_age is now uniformly malformed; verifiers
    MUST reject per §4.2 Step 1. Closes the v0.2 REQUIRED-elevation-
    with-retained-default contradiction.

(2) §6.5 Constraint Stripping — added normative sentences requiring
    verifiers to reject mandates whose Layer 2 signature does not
    validate over the full constraint list, and prohibiting acceptance
    of subset-signed mandates. Closes the zero-normative-keyword gap
    identified by LembaGang's RFC 2119 audit.

Three consumer-policy additions (Doug's Apr 18 17:42 proposal comment
4274241447, LembaGang-approved in comment 4274435668):

(3) stale_cache_fallback_permitted OPTIONAL boolean field (default
    false):
    - §4 schema row added (OPTIONAL per LembaGang (i) at 4274435668;
      default-false; payment-execution MUST NOT set true).
    - §4 Field Constraints bullet with boolean-type hygiene clause:
      "if present, MUST be a strict boolean. Non-boolean values
      (including string "false", null, or numeric) MUST be rejected
      as malformed per §4.2 Step 1."
    - §4.2 pseudocode Step 1 type-check.
    - §6.8 "Fail-closed on fetch failure" paragraph: stale-cache
      sentences replaced with field-driven text (MAY use expired cache
      when true, MUST produce violation when false/absent, payment-
      execution MUST NOT set true).

    Shape follows the v0.3.2 rule-narrowing: REQUIRED remains the right
    pattern where no nontrivial default is safe across deployment
    classes (max_attestation_age); OPTIONAL-with-default is the right
    pattern where a single default is correct for almost all
    deployments (stale_cache_fallback_permitted). Parallel-construction
    Field Constraints bullet matches the max_attestation_age pattern.

(4) §6.8 grace-window discoverability: issuers SHOULD publish
    rotation-start and grace-window-end timestamps through an auditable
    channel. Channel MAY be out-of-band (release notes, status page,
    signed rotation announcement) or in-band via a JWKS top-level
    metadata field (e.g., rotation_announcement with
    rotation_started_at / previous_kid / new_kid / grace_window_end).
    SHOULD is on discoverability, not form. Future revision may elevate
    to REQUIRED if the WG converges on a canonical in-band mechanism.

(5) §6.3 JWKS URL migration paragraph: trusted_jwks URL change is a
    new-mandate event by design. Migration path: issuer publishes a
    new JWKS at the new URL; mandate issuers emit new mandates
    targeting the new URL; existing mandates expire naturally via
    exp. Deliberate cost/benefit: trust root cannot be silently
    relocated, at the cost of non-free URL migration.

(6) SHALL→MUST normalization NOT NEEDED: post-audit verification on
    both specs shows all SHALL references sit in the RFC 2119
    Notational Conventions boilerplate (line 67 on agent-intent#22, line 66 on
    agent-intent#9); zero substantive usage elsewhere. LembaGang's P3 finding
    withdrawn on PR agent-intent#9, symmetric on agent-intent#22.

§9 changelog: v0.4-draft row added above v0.3.1-draft.

No architectural changes. No family-wide changes. No InsumerAPI-side
code changes required. Co-drafted with LembaGang (Headless Oracle)
over PRs agent-intent#9 and agent-intent#22.

Co-Authored-By: LembaGang <127877551+LembaGang@users.noreply.github.com>
…my with populated wallet_state field table

Mirrors PR agent-intent#9 v0.5.1-draft (commit 7b97827, LembaGang, Headless Oracle)
into environment.wallet_state §4.8. Closes the v0.5 round on this spec
per LembaGang's comment 4276111822: "You commit v0.5 §4.8 on PR agent-intent#22:
field table per the Note on family coordination, with
required_condition_hashes and attestation_request_body under
per-type-evaluation-mechanism-bound." Single v0.5-draft commit on the
wallet_state side; document header bumped 0.2-draft to 0.5-draft
(capturing v0.3 / v0.3.1 / v0.4 header omissions).

Three scope categories ported verbatim from 7b97827 as family-wide
prose:

- family-wide-trust-root-agnostic — identical semantics across every
  environment.* constraint type.
- per-type-trust-root-mechanism-bound — semantics bound to the specific
  trust-root mechanism (RFC 7517 JWKS here; RFC 8615 key registry on
  environment.market_state).
- per-type-evaluation-mechanism-bound — semantics bound to the type's
  evaluation-mechanism output shape or wire-protocol binding to the
  evaluator.

Field table populated for current environment.wallet_state fields:

- max_attestation_age               family-wide-trust-root-agnostic  (§4.6)
- trusted_jwks                      per-type-trust-root-mechanism-bound  (§6.3)
- stale_cache_fallback_permitted    per-type-trust-root-mechanism-bound  (§6.8)
- subject_wallet                    per-type-evaluation-mechanism-bound  (§5.5)
- required_condition_hashes         per-type-evaluation-mechanism-bound  (§4.1)
- attestation_request_body          per-type-evaluation-mechanism-bound  (§4.1)

Rationale for subject_wallet placement under
per-type-evaluation-mechanism-bound: the swap test is the load-bearing
argument. Replace ES256+JWKS with an Ed25519 scheme that binds wallets
through a different mechanism, and subject_wallet still does the §5.5
per-member disambiguation job against whatever the new format calls
the wallet identifier. The sub: <wallet> binding lives in the
attestation payload — the issuer's trust-root-specific claim that the
signed attestation is about this wallet — not in the constraint field.
subject_wallet as a constraint field is the verifier-side matching
slot: it names which wallet the attestation must prove pass for. That
matching function survives any trust-root mechanism swap. The
counter-case (trust-root-bound via JWT sub to wallet) collapses under
the swap test: the binding lives in the attestation, not in the
constraint's subject_wallet slot.

Rule for future fields and Relationship to §4.6/§4.7 ported verbatim
from 7b97827 as family-wide prose. Note on family coordination is
reciprocal, pointing at PR agent-intent#9 commit 7b97827 per the §5.5 precedent
(PR agent-intent#22 commit 7848bc2 points at PR agent-intent#9 commit 7a8987c).

No algorithm changes; no security-model changes; no §6.* changes; no
§7.* changes; no InsumerAPI-side code changes required.

Co-Authored-By: LembaGang <127877551+LembaGang@users.noreply.github.com>
…nale entries

Closes the §4.8 field-table coverage asymmetry flagged by LembaGang in
comment 4276249269 (6/9 wallet_state constraint fields declared at v0.5;
missing attestation_url, expected_kid, expected_issuer). Path (1)
selected over narrowing the §4.8 preamble's universal quantifier per
Doug's comment 4276295574 and LembaGang's green-light in comment
4276315303.

Three table rows added to §4.8:

- attestation_url            family-wide-trust-root-agnostic     (§4.1)
- expected_kid               per-type-trust-root-mechanism-bound (§6.3)
- expected_issuer            per-type-trust-root-mechanism-bound (§6.3)

Three rationale entries integrated into the §4.8 post-table paragraph
in category order. The attestation_url entry is a three-sentence defense
block pre-empting the §4.8-internal question of why the URL is
family-wide when attestation_request_body (which targets the same URL)
is per-type-evaluation-mechanism-bound: the placement lands on the same
basis as max_attestation_age in §4.6 — identical semantic role across
types, with per-type variance localised at neighbouring fields (HTTP
verb, request-body shape). expected_kid and expected_issuer are
one-sentence entries semicolon-joined with their market_state sibling
notes, classified on JOSE-signing-stack specificity: both are JWT
header/claim bindings parallel-but-mechanism-specific on
environment.market_state, which uses an RFC 8615 key registry
(oracle_public_key_id) and derives issuer identity from the attestation
payload rather than from a constraint-level JOSE iss binding.

Document header stays at 0.5-draft — patch-level refinement, not a new
minor version (matches LembaGang's convention on commit 7b97827 where
PR agent-intent#9 shipped v0.5.1-draft with header unchanged).

No schema changes; no algorithm changes; no security-model changes; no
changes outside §4.8; no InsumerAPI-side code changes required.
LembaGang to mirror onto PR agent-intent#9 as v0.5.2-draft with attestation_url
(family-wide-trust-root-agnostic), oracle_public_key_id
(per-type-trust-root-mechanism-bound), and expected_status
(per-type-evaluation-mechanism-bound — status-enum analog to
required_condition_hashes) per comment 4276315303.

Co-Authored-By: LembaGang <127877551+LembaGang@users.noreply.github.com>
…p mirror of PR agent-intent#9 v0.5.3

Mirrors PR agent-intent#9 v0.5.3 (commit 85c6594, LembaGang, Headless Oracle) onto
environment.wallet_state.

Two touch points:

- §5.2 body gains the short-circuit sentence verbatim from PR agent-intent#9 §5.2:
  "If any `environment.*` constraint fails, the agent MUST NOT evaluate
  remaining constraints and MUST NOT proceed to L3 creation."
  Brings §5.2 body to parity with agent-intent#9. The pre-existing "inherited 1:1
  from §5.2 of environment.market_state" rationale note is now truthful
  about body content, not only rationale.

- §5.5 Block 3 gains the family-wide bridge sentence verbatim from PR agent-intent#9
  §5.5 Block 3 at 85c6594:
  "The completeness requirement applies to the verifier-side L3-acceptance
  evaluation path; agent-side pre-L3-creation evaluation is governed by
  §5.2's short-circuit clause, which requires agents to stop at the first
  `environment.*` failure as a fail-closed agent-side halt distinct from
  the verifier's diagnostic-completeness obligation."

Resolves the §5.2/§5.5 register tension flagged in PR agent-intent#9's RFC 2119 audit
P3-1. §5.2 binds agents at pre-L3-creation (short-circuit, fail-closed).
§5.5 binds verifiers at L3-acceptance (completeness, diagnostic). Both
rules stand; the bridge sentence makes the phase distinction explicit so
neither reads as contradicting the other.

Venue Option A (§5.5 Block 3 placement). Precision rewrite adopted verbatim
per the precision flag posted on PR agent-intent#9 (permits → requires, self-gating
optimization → fail-closed agent-side halt).

Document header stays at 0.5-draft; v0.5.3 is a patch-level refinement per
the convention established in 7b97827. No algorithm changes; no security-
model changes; no InsumerAPI-side code changes required.

Queued for v0.5.4 per LembaGang's observation on comment 4279340548: §5.2
forward-pointer to §5.5 Block 3 for MCP/section-isolation retrieval paths;
plus PR agent-intent#9 P3-2 (§2.3 descriptive/normative register) and P3-3 (§2.4
RECOMMENDED/SHOULD redundancy) — both agent-intent#9-local.

Co-Authored-By: LembaGang <127877551+LembaGang@users.noreply.github.com>
…preamble clarification + §4.8 rows + §6.9 new section

Closes the third and final held-back item from LembaGang's Apr 16 review
(first: §5.5 family composition, shipped v0.3/v0.3.1; second: §6.8 JWKS
caching + §6.5 constraint stripping + stale_cache, shipped v0.4; third:
cross-chain temporal consistency, this commit).

Scope locked with LembaGang on Apr 19 (comment 4276613295: three-scenario
walk-through of market_state's temporal surface confirmed no cross-venue
skew distinct from per-attestation freshness; Option 1 wallet_state-local
placement ratified). Apr 20 ratification (comment 4279340548) confirmed
boundary framing reads clean and §4.8 taxonomy extension to JWT claims
accepted.

Five touchpoints:

(1) §4 schema — two new OPTIONAL fields: finality_depth (positive
integer, minimum block confirmations past attested block; mandate-
issuer-declared) and max_cross_chain_skew_seconds (positive integer,
maximum tolerated wall-clock divergence across chain-tip timestamps for
multi-chain mandates). Companion Field Constraints bullets matching the
stale_cache_fallback_permitted malformedness pattern.

(2) §4.1 unchanged. The v0.2 provider-neutrality contract (7 REQUIRED
core claims + results/blockNumber/blockTimestamp OPTIONAL for second-
conformant-implementation portability across non-EVM chains) is
preserved; no elevation of blockTimestamp to REQUIRED.

(3) §4.8 preamble one-sentence inline clarification placed between the
three scope-category bullets and the "Scope declarations..." header:
"Within §4.8, 'field' encompasses both constraint schema fields declared
in §4 and, where operationally relevant, JWT claims declared in §4.1."
Preserves verbatim cross-spec byte-identity of the preamble sentence and
the three category bullets with PR agent-intent#9 §4.8 at 85c6594.

(4) §4.8 field table + rationale — three new rows under per-type-
evaluation-mechanism-bound: blockTimestamp (references existing §4.1
OPTIONAL JWT claim), finality_depth (references new §4 constraint
field), max_cross_chain_skew_seconds (references new §4 constraint
field). Rationale paragraph extended with three trailing semicolon-
joined sentences in category order paralleling the v0.5.1/v0.5.2
structure; blockTimestamp's rationale inlines a sibling-no-analog
clarification pre-empting the WG-reviewer question of why
environment.market_state has no corresponding entry.

(5) §6.9 Cross-Chain Temporal Consistency — new security-considerations
section between §6.8 JWKS caching/rotation and §7 Reference
Implementation. Six blocks:
  - §6.7 adjacency opening: verifier↔issuer wall-clock skew vs
    attested-block↔chain-tip skew — adjacent but distinct.
  - Orthogonal-axes boundary sentence: pre-acceptance×cross-chain via
    max_cross_chain_skew_seconds vs post-acceptance×within-chain via
    reorg advisory SHOULD.
  - Finality-depth measurement: confirmation depth is derived from the
    verifier's independent chain read at verification time; no
    additional JWT claim required from issuer, preserving the v0.2
    provider-neutrality contract on §4.1.
  - Reorg remediation (advisory): verifier-bound SHOULD on re-verification
    at settlement time; explicitly not a synchronous chain-finality
    mandate (would overconstrain verifier implementations).
  - Measurement basis for max_cross_chain_skew_seconds: verifier MUST
    measure skew across the mandate's environment.* attestations using
    blockTimestamp when present, falling back to iat; skew computed in
    Unix seconds with explicit canonicalization (ISO 8601 blockTimestamp
    values per §4.1 MUST be converted to integer Unix seconds, truncating
    sub-second precision, before comparison); issuer SHOULD include
    blockTimestamp on chains with a block-time anchor, MAY omit on chains
    without (non-EVM chains; iat governs cross-chain skew measurement
    and max_attestation_age bounds per-attestation freshness in that
    case).
  - Placement rationale: §4.8 forward rule against speculative family-
    wide §4.9 proliferation. market_state has no cross-venue temporal
    concern distinct from per-attestation freshness (three-scenario
    walk-through confirmed Apr 19). Future WG elevation path to §4.9
    preserved.

Document header bumps 0.5-draft → 0.6-draft; new-section-level surface
matches the v0.5 §4.8-addition precedent for minor-version release
discipline.

Queued for v0.5.4 (LembaGang's Apr 20 observation on comment 4279340548):
§5.2 forward-pointer to §5.5 Block 3 for MCP/section-isolation retrieval
paths; plus PR agent-intent#9 P3-2 (§2.3 descriptive/normative register) and P3-3
(§2.4 RECOMMENDED/SHOULD redundancy) — both agent-intent#9-local.

No algorithm changes; no security-model changes beyond §6.9 additions;
no InsumerAPI-side code changes required.

Co-Authored-By: LembaGang <127877551+LembaGang@users.noreply.github.com>
…sub-second truncation asymmetry as intentional
…f PR agent-intent#9 01490df

Mirrors PR agent-intent#9 v0.5.5-draft Appendix C (commit 01490df, LembaGang, Headless
Oracle) per LembaGang's Apr 21 22:37 UTC converge signal on PR agent-intent#9 comment
4292298210. Six sections at C.1 through C.6:

- C.1 Purpose — anchors in v0.5.4 §2.3/§2.5 and v0.6.1 §6.9 as concrete drivers
- C.2 Normative vs. descriptive register — definitions + v0.5.4 §2.3 worked example
- C.3 Rules for the environment.* family (five rules: RFC 2119 keywords in
  normative register, lowercase synonyms in descriptive register, redundancy
  avoidance, application-layer vs. transport-layer scope, forward rule for
  new sections)
- C.4 Open questions for working group (Q1 informative-vs-normative
  classification, Q2 audit cadence, Q3 scope over time)
- C.5 Current instances — catalog deferred to a future revision
- C.6 Relationship to §1 Notational Conventions

Letter alignment C-to-C confirmed, no offset (Appendix A Attestation Test
Vectors + Appendix B Failure Mode Quick Reference + Appendix C Register
Discipline on both sides).

Two localisation surfaces; C.2 through C.6 byte-identical to PR agent-intent#9 01490df:

(1) C.1 prose flip — `environment.market_state` attached to (PR agent-intent#9) and
    `environment.wallet_state` attached to (this specification). Trailing
    "§2.3/§2.5 on agent-intent#9, §6.9 on agent-intent#22" PR-history refs verbatim.

(2) Coordination Note-block rewrite — resolves the "pending confirmation of
    current appendix count on PR agent-intent#22" caveat (confirmed in LembaGang's 22:37
    converge signal) and flips port direction from drafted-for to mirrored-from,
    naming commit 01490df as source.

Douglas's four dispositions on PR agent-intent#9 comment 4292173322 all landed as-drafted
per LembaGang's converge signal: (a) self-reference tension — MUSTs at
C.3.1/C.3.4/C.3.5 kept, preamble does the binding-scope work; Q1
informative-with-normative-cross-references; Q2 deferred to WG with mild
preference for continued ad-hoc cadence (forward-scoped if formalised, no
retroactive burden); Q3 kept open as drafted with four properties verbatim
(provider neutrality, peer-author coordination discipline, patch-level
versioning conventions, lockstep commit patterns).

Document header stays at 0.6-draft per patch-level convention established at
v0.5.1 and reaffirmed at v0.5.3 / v0.6.1; v0.6.2 is a patch-level refinement.

No algorithm changes; no security-model changes; no InsumerAPI-side code
changes required.

Co-Authored-By: LembaGang <127877551+LembaGang@users.noreply.github.com>
First coordination commit following Mastercard's PR agent-intent#23 merge into upstream/main.
Aligns environment.wallet_state RFC with the field-alignment-v2 normative changes
from agent-intent#23 (Reda, Apr 20 2026).

No semantic changes to `environment.wallet_state` itself. Purely downstream
propagation of transactional-constraint renames that appear in examples and
prose cross-references within this RFC:

- VCT version suffix: `mandate.checkout.open` -> `mandate.checkout.open.1`
  (3 occurrences: §2.2 dual-mode prose, §4 Appears In, §4.5 composition example)
- VCT version suffix: `mandate.payment.open` -> `mandate.payment.open.1`
  (2 occurrences: §2.2 dual-mode prose, §4 Appears In)
- Constraint type pluralisation: `mandate.checkout.allowed_merchant` ->
  `mandate.checkout.allowed_merchants` (1 occurrence in §4.5 composition example)
- Constraint field generalisation: `allowed_merchants` -> `allowed`
  (1 occurrence, paired with the pluralisation above)
- §5.5 Block 3 prose collapse: `(mandate.*, payment.*)` -> `(mandate.*)`
  (reflects PR agent-intent#23's move of payment constraints under the mandate.* prefix)

Additive PR agent-intent#23 fields (match_mode, constraint_policy, risk_data) are out of
scope for this RFC — they belong to transactional constraint types, not the
environment.* family.

Signed-off-by: Douglas Borthwick <256362537+douglasborthwick-crypto@users.noreply.github.com>
…SDT alignment

Adds Appendix D listing the running-code implementations of the
environment.* family, per RFC 6982. Aligns §7.1 + §7.4 prose with
production /v1/keys/buy payment-method enumeration.

Scope of this revision:

- Appendix D.1 records InsumerAPI as the running implementation of
  environment.wallet_state. Lean RFC 6982 status table (License,
  endpoints, signing algorithm, kid, JWT TTL, coverage, agent-native
  key provisioning, reference verifiers); conformance pointer set
  for §4.1 / §4.2 / §4.6 / §4.7 / §4.8 / §5.5 / §6.5 / §6.8 / §6.9;
  pointer to §7 for full reference-implementation prose rather than
  duplicating.
- Appendix D.2 records Headless Oracle as the running implementation
  of the sibling environment.market_state constraint type per PR agent-intent#9.
  Listed for environment.* family completeness; canonical
  Implementation Status appendix for environment.market_state
  belongs in PR agent-intent#9 (editor's call on Michael Msebenzi / LembaGang's
  side).
- Appendix D.3 disclaimer states that listing is not endorsement and
  verifiers MUST independently verify per §4.2 regardless of
  Appendix D listing.
- §7.1 + §7.4 source-of-truth alignment: POST /v1/keys/buy payment
  methods updated from "USDC or BTC" / "USDC (or BTC)" to
  "USDC, USDT, or BTC" matching production behavior (openapi.yaml
  PaymentChainId enumeration). §7.4 prose around agent-key-bootstrap
  rationale generalised from "the authority to spend USDC" to
  "on-chain spending authority" — drops the canonical-token
  enumeration mismatch with §7.4 endpoint enumeration above it
  without losing the rhetorical argument.
- §9 Changelog: v0.6.4-draft row added at the top of the table.

Per RFC 6982 §2, Appendix D is intended to be removed by the RFC
Editor before any final standards-track publication; the GitHub
history of this Internet-Draft retains it permanently as evidence
of priority.

Document header stays at 0.6-draft; v0.6.4 is a patch-level
refinement adding an informative appendix and aligning §7 prose
with production. No algorithm changes, no security-model changes,
no §4 schema changes, no InsumerAPI-side code changes required.

Sibling-mirror coordination: independent of the parallel Appendix D
landing on the environment.market_state side per LembaGang's
LembaGang/verifiable-intent commit 21a156c anchor ("a parallel
Appendix D on PR agent-intent#22 is the editor's call on the
environment.wallet_state side and is expected to land independently
on Douglas Borthwick's timing"). Sole-authored, mirroring the v0.6.3
propagation discipline — no Co-Authored-By trailers.
…-type)

Adds family-wide algorithm-deprecation prose mirroring
draft-borthwick-msebenzi-environment-state-00 v0.2-draft §4.3 family-wide
SHOULD ("Type specification authors SHOULD specify, in the type's
specification, a deprecation mechanism for the type's MUST-implement
algorithm before that algorithm is needed").

Adds per-type deprecation mechanism for environment.wallet_state:
conditions (NIST/IETF JOSE/RFC 8725 update or cryptographic break),
timeline (12-month verifier-migration window from minor-version revision
publication), backward-compatibility (parallel verification during window;
mandate issuer migration on JWKS readiness).

Updates §4.7 PR agent-intent#9 coordination Note to reflect PR agent-intent#9 §4.7 as the
verbatim-portable target (PR agent-intent#9's algorithm-agility section sits at §4.7);
family-wide prose remains verbatim-portable; deprecation mechanism block
joins table rows in the per-type-swap surface.

Co-Authored-By: LembaGang <127877551+LembaGang@users.noreply.github.com>
@douglasborthwick-crypto douglasborthwick-crypto force-pushed the rfc-environment-wallet-state branch from a14a801 to d0c2e31 Compare May 12, 2026 20:30
LembaGang added a commit to LembaGang/verifiable-intent that referenced this pull request May 31, 2026
…hm agility, impl alignment

Addresses coordination with PR agent-intent#22 (Douglas Borthwick, InsumerAPI).

Four structural changes:

1. Namespace framing: new §2.3 documents sibling relationship to
   environment.wallet_state. Abstract, §2.1, §2.2 updated to reflect
   environment.* family. §5.2 execution-order rationale generalized.

2. Attestation freshness: max_age_seconds renamed to max_attestation_age
   for lockstep alignment with agent-intent#22 §4.6. Elevated to REQUIRED with
   normative default of 60. New §4.6 documents TOCTOU rationale using
   market-execution precedents (2010 Flash Crash, circuit breaker races,
   2020 WTI crude oil futures) and family-wide semantics.

3. Algorithm agility: New §4.7 lifted from agent-intent#22 §4.7 with Ed25519 as
   MUST-implement, ES256/Ed448/ES384/ES512 as extension set. RFC 8725
   §3.1 hook. Per-type MUST-implement + SHOULD/MAY, fail-closed
   negotiation not silent downgrade.

4. Spec-implementation alignment: conformance-tested spec against
   deployed reference implementation before committing. Three
   pre-existing misalignments fixed: attestation field key_id ->
   public_key_id (matches deployed receipt shape), registry lookup
   k.id -> k.key_id (matches deployed /.well-known/oracle-keys.json),
   new envelope clause in §4.1 disambiguating unsigned wrapper fields
   (discovery_url, extensions, nested receipt) from the signed
   attestation subset. Zero Worker changes.

§4.5 expanded with joint environment.market_state +
environment.wallet_state composition example. §6.3 notes complementary
JWKS pattern from agent-intent#22 §6.3. §8 Q2 references agent-intent#22 §6.3; §8 Q6 added on
family-wide subject binding (mirrors agent-intent#22 §8 Q5). Lifecycle sections
renumbered (§2.3 -> §2.4, §2.4 -> §2.5).

Appendix A test vector and Appendix B failure table updated for field
name alignment. §7.2 and §7.3 reference implementations updated.

No changes to verification algorithm, fail-closed semantics, or security
model. Zero Headless Oracle code changes required.

Signed-off-by: Michael Msebenzi <127877551+LembaGang@users.noreply.github.com>
LembaGang added a commit to LembaGang/verifiable-intent that referenced this pull request May 31, 2026
Adds §5.5 Family Composition in response to the held-back follow-ups
from PR agent-intent#22 v0.2 review (conjunction semantics, L3 gate, per-member
diagnostic output). Co-drafted with Douglas Borthwick (InsumerAPI) over
PRs agent-intent#9 and agent-intent#22; mirrors PR agent-intent#22 §5.5 (commit 85cfaa0) with two
refinements agreed in PR agent-intent#22 discussion:

- Gap 1 (L3 gate timing): verifiers MUST evaluate every environment.*
  constraint to completion before refusing Layer 3; short-circuit
  evaluation is non-conforming. Composes with §5.2 ordering.

- Gap 2 (per-member disambiguation): every violation entry carries
  both an array-index machine identifier and a per-type human-readable
  identifier (MIC for market_state, subject_wallet for wallet_state).
  The §4.5 multi-exchange example (XNYS + XLON) is the driving case.

Rationale presents semantic ("independent questions compose as AND")
and architectural ("failure mode must be gating, or the type isn't in
the family") arguments as co-equal — conjunction as a family
membership criterion, not a per-type design decision. Load-bearing for
future environment.* types (regulatory_status, counterparty_credit).

Drafted as standalone block adoptable verbatim in environment.wallet_state
§5.5 with the per-type distinguishing-field row swapped. Same pattern
as §4.7 — one family-wide question, one answer, two specs.

No changes elsewhere in the spec; no verification algorithm, fail-closed,
or security-model changes; no Headless Oracle code changes required.

Co-Authored-By: Douglas Borthwick <douglasborthwick-crypto@users.noreply.github.com>
Signed-off-by: Michael Msebenzi <127877551+LembaGang@users.noreply.github.com>
LembaGang added a commit to LembaGang/verifiable-intent that referenced this pull request May 31, 2026
…back_permitted

Lifts the family-wide additions shipped by Douglas in PR agent-intent#22 bb7af90 with
terminology adaptation for market_state's key-discovery architecture.

Additions:
- New §6.8 Key Registry Caching and Key Rotation: lifted from bb7af90's
  §6.8 JWKS Caching and Key Rotation with systematic terminology swaps
  (JWKS → RFC 8615 key registry, kid → key_id, trusted_jwks → issuer-
  derived oracle key registry URL). All MUST/SHOULD/MAY keywords and
  paragraph ordering preserved verbatim. Includes grace-window SHOULD
  paragraph with rotation_announcement metadata example adapted to
  market_state's key registry shape.
- stale_cache_fallback_permitted OPTIONAL boolean field (§4 schema row,
  §4 Field Constraints bullet with "If present MUST be boolean" hygiene
  clause per Douglas's v0.4 addition, §4.2 Step 1 type-check, §6.8
  companion paragraph). Default false; payment-execution MUST NOT set
  true.

Intentional asymmetry — not lifted:
- §6.3 JWKS URL migration paragraph from bb7af90. wallet_state's
  trusted_jwks is a signed L2 constraint field (user-signed); market_
  state's registry URL is derived from the oracle's issuer field
  (oracle-signed). The underlying property Douglas's paragraph addresses
  — trust-root URL as rigid mandate binding — does not exist in
  market_state. This asymmetry is pre-existing and already documented
  in §6.3's JWKS/RFC-8615 coexistence paragraph. The coordination work
  this week treated §6.3 as family-symmetric; the spec itself says
  otherwise. Formalizing trust-root-binding as an explicit family-
  charter dimension queued for v0.5.

Scope of family-wide claims:
- §4.6 family-wide framing continues to cover max_attestation_age only.
- stale_cache_fallback_permitted is scoped per-type with parallel
  semantics to PR agent-intent#22's version. Field governs stale-cache fallback on
  the trust-root mechanism the constraint uses; the mechanism differs
  between types, so the field's operational scope is per-type.

Changelog: 0.4-draft row added above 0.3.2-draft.

Co-Authored-By: Douglas Borthwick <256362537+douglasborthwick-crypto@users.noreply.github.com>
Signed-off-by: Michael Msebenzi <127877551+LembaGang@users.noreply.github.com>
LembaGang added a commit to LembaGang/verifiable-intent that referenced this pull request May 31, 2026
…chanism-bound

Adds a third scope category to §4.8 in response to the taxonomy gap Douglas
Borthwick surfaced on PR agent-intent#22's v0.5 mirror: wallet_state fields
`required_condition_hashes` and `attestation_request_body` are per-type
scope but not bound by trust-root mechanism — their binding is to the
constraint type's evaluation mechanism (output shape or wire-protocol).

Three scope categories now recognised:

- family-wide-trust-root-agnostic (max_attestation_age)
- per-type-trust-root-mechanism-bound (stale_cache_fallback_permitted)
- per-type-evaluation-mechanism-bound (empty at v0.5.1; no market_state
  fields placed there; declaration only)

The new category preserves the -mechanism-bound suffix, keeping the
taxonomic level parallel to the existing per-type category (trust-root
mechanism vs. evaluation mechanism). Umbrella covers both the evaluator's
output shape (condition-hash sets vs. status enum) and the wire-protocol
binding to the evaluator (request body shape).

Preamble ("recognises three scope categories") and forward rule ("beyond
the three currently recognised") updated for consistency. The SHOULD
clause on placement under existing categories holds: the clause guards
against speculative proliferation, not evidence-based category addition
when two fields on a sibling spec clearly belong outside the two existing
categories.

Charter declaration is family-wide; field-table population for
environment.wallet_state sits with PR agent-intent#22's v0.5 mirror. Same standalone-
block pattern as §5.5 / §6.8 — one family-wide question, one answer, two
specs; PR agent-intent#9 leads the taxonomy, PR agent-intent#22 mirrors with populated field rows.

v0.5.1 is a patch-level refinement of v0.5. No header bump — the
document-level version marker stays at 0.5-draft; the v0.5.1 row in §9
records the taxonomy change. Forward rule holds: further scope categories
beyond these three are working-group revisions.

No algorithm changes; no security-model changes; no Headless Oracle code
changes required.

Co-Authored-By: Douglas Borthwick <256362537+douglasborthwick-crypto@users.noreply.github.com>
Signed-off-by: Michael Msebenzi <127877551+LembaGang@users.noreply.github.com>
LembaGang added a commit to LembaGang/verifiable-intent that referenced this pull request May 31, 2026
Adds three rows to the §4.8 field table covering remaining environment.market_state constraint fields, extends the post-table rationale paragraph with three new sentences, and reorganises the table to group by scope category matching PR agent-intent#22 v0.5 layout.

Field rows added:

- attestation_url (family-wide-trust-root-agnostic, §4.1)

- oracle_public_key_id (per-type-trust-root-mechanism-bound, §6.3)

- expected_status (per-type-evaluation-mechanism-bound, §4.1)

Rationale sentences added, one per new field, paralleling the existing max_attestation_age and stale_cache_fallback_permitted entries. The attestation_url rationale pre-empts the WG-reviewer question of why the URL field is family-wide while attestation_request_body on the sibling specification is per-type-evaluation-mechanism-bound: the semantic role of the URL field is identical across types, per-type variance is localised at neighbouring wire-protocol fields (per-type §4.1 interface + attestation_request_body on environment.wallet_state), placement basis identical to max_attestation_age in §4.6.

Responds to PR agent-intent#22 review thread flagging preamble-table asymmetry: §4.8's preamble requires every field in the family to declare its scope, but the v0.5 / v0.5.1 tables declared scope for a subset only. v0.5.2 closes the gap on the environment.market_state side. Parallel to PR agent-intent#22 v0.5.1 at commit 4effcb8.

Document header stays at 0.5-draft; v0.5.2 is a patch-level refinement. No algorithm changes; no security-model changes; no Headless Oracle code changes required.

Co-Authored-By: Douglas Borthwick <256362537+douglasborthwick-crypto@users.noreply.github.com>
Signed-off-by: Michael Msebenzi <127877551+LembaGang@users.noreply.github.com>
LembaGang added a commit to LembaGang/verifiable-intent that referenced this pull request May 31, 2026
Inserts a single bridge sentence into §5.5 Block 3 ("L3 execution gate and completeness") that names the phase distinction explicitly: the §5.5 completeness requirement applies to the verifier-side L3-acceptance evaluation path; agent-side pre-L3-creation evaluation is governed by §5.2's short-circuit clause, which requires agents to stop at the first environment.* failure as a fail-closed agent-side halt distinct from the verifier's diagnostic-completeness obligation.

Resolves the §5.2/§5.5 register tension flagged in the RFC 2119 audit P3-1. §5.2 requires agents to short-circuit on the first environment.* failure (agent-phase, fail-closed). §5.5 Block 3 requires verifiers to evaluate every environment.* constraint to completion (verifier-phase, diagnostic-completeness). On their face these read as contradictory; the bridge sentence makes the phase distinction load-bearing and removes the apparent conflict without changing either rule.

Wording refined on PR agent-intent#9 with Douglas Borthwick:

- Option A venue: bridge sentence placed in §5.5 Block 3, immediately after the verifier-side completeness sentence, rather than in §5.2 or as a free-standing block. Keeps the disambiguation co-located with the rule it disambiguates.

- Precision rewrite: permits → requires (§5.2 short-circuit is normative agent obligation, not optional optimisation); self-gating optimization → fail-closed agent-side halt (correctly characterises the agent-phase halt as a safety property, not a performance choice). Douglas eyeball-acked the precision rewrite on PR agent-intent#9.

PR agent-intent#22 v0.5.3 mirror by Douglas will add the §5.2 short-circuit body sentence plus the same §5.5 Block 3 bridge in lockstep, so the family lands the resolution identically across both type specifications.

Document header stays at 0.5-draft; v0.5.3 is a patch-level refinement per the convention established in 7b97827. No algorithm changes; no security-model changes; no Headless Oracle code changes required.

Co-Authored-By: Douglas Borthwick <256362537+douglasborthwick-crypto@users.noreply.github.com>
Signed-off-by: Michael Msebenzi <127877551+LembaGang@users.noreply.github.com>
LembaGang added a commit to LembaGang/verifiable-intent that referenced this pull request May 31, 2026
…2.5 register polish

Four touchpoints: §5.2 forward-pointer closing MCP/section-isolation discovery gap; §4.8 preamble port from PR agent-intent#22 v0.6 feb3292 by Douglas Borthwick; §2.3 register polish (P3-2); §2.5 register polish (P3-3). Document header stays at 0.5-draft. §9 Changelog row added.

Co-Authored-By: Douglas Borthwick <256362537+douglasborthwick-crypto@users.noreply.github.com>
Signed-off-by: Michael Msebenzi <127877551+LembaGang@users.noreply.github.com>
LembaGang added a commit to LembaGang/verifiable-intent that referenced this pull request May 31, 2026
Formalises the normative-vs-descriptive register discipline applied across the environment.* family in multiple patch-level revisions (v0.5.4 §2.3/§2.5 on agent-intent#9, v0.6.1 §6.9 on agent-intent#22) as an explicit charter property.

Six sections at C.1 through C.6:

- C.1 Purpose — anchors in v0.5.4 §2.3/§2.5 and v0.6.1 §6.9 as concrete drivers
- C.2 Normative vs. descriptive register — definitions + worked example from v0.5.4 §2.3
- C.3 Rules for the environment.* family:
  * C.3.1 RFC 2119 keywords in normative register
  * C.3.2 Lowercase synonyms in descriptive register
  * C.3.3 Redundancy avoidance (v0.5.4 §2.5 as worked example)
  * C.3.4 Application-layer vs. transport-layer scope (v0.6.1 §6.9 as worked example)
  * C.3.5 Forward rule for new sections
- C.4 Open questions — three for WG input:
  * Q1 Informative vs. normative appendix classification
  * Q2 Register-discipline audit cadence
  * Q3 Scope of Appendix C over time (evolves with practice; WG input welcome)
- C.5 Catalog of current instances — deferred to a future revision
- C.6 Relationship to §1 Notational Conventions

Skeleton only — shape and rules stated, full prose and exhaustive catalog deferred to post-convergence revision. Adoptable verbatim on PR agent-intent#22 Appendix C following the (a) pattern established for §4.8.

Document header stays at 0.5-draft per patch-level convention.

No algorithm changes; no security-model changes; no Headless Oracle code changes required.

Co-Authored-By: Douglas Borthwick <256362537+douglasborthwick-crypto@users.noreply.github.com>
Signed-off-by: Michael Msebenzi <127877551+LembaGang@users.noreply.github.com>
LembaGang added a commit to LembaGang/verifiable-intent that referenced this pull request May 31, 2026
Adds Appendix D listing the running-code implementations of the environment.*
family known to the editors at the time of writing, per RFC 6982.

Scope of this revision:

- Appendix D.1 records Headless Oracle as the reference implementation of
  environment.market_state. Endpoints, Ed25519 signing per §4.7, coverage of
  28 global exchanges (25 ISO 10383 MICs + 3 convention MICs for crypto-native
  venues), reference verifier at github.com/headlessoracle/demo-agent (~150
  lines, MIT), architectural rationale at github.com/headlessoracle/essays,
  and the conformance pointer set for §4.1, §4.2, §4.6, §4.7, §6.5, §6.8.
  Records the 2026-04-03 x402 settlement infrastructure validation tx on
  Base mainnet (payer wallet self-funded for end-to-end test, not commercial
  revenue; first external x402 transaction observed 2026-04-17).
- Appendix D.2 records InsumerAPI (Skye Meta Corp, PR agent-intent#22) as the running
  implementation of the sibling environment.wallet_state constraint type.
  Sourced from PR agent-intent#22's property table: ES256 / P-256, kid insumer-attest-v1,
  1800-second JWT TTL, 33-chain coverage. Listed for environment.* family
  completeness; the canonical Implementation Status appendix for
  environment.wallet_state belongs in that specification.
- Appendix D.3 disclaimer states that listing is not endorsement and verifiers
  MUST independently verify per §4.2 regardless of Appendix D listing.
- §9 Changelog: v0.5.7-draft row added at the top of the table.

Per RFC 6982 §2, Appendix D is intended to be removed by the RFC Editor before
any final standards-track publication; the GitHub history of this Internet-
Draft retains it permanently as evidence of priority.

Document header stays at 0.5-draft; v0.5.7 is a patch-level refinement adding
an informative appendix only. No algorithm changes, no security-model changes,
no §4 schema changes, no Headless Oracle code changes required, test count
unchanged (1031+ as of the Apr 24 telemetry hardening sprint baseline).

Sibling-mirror coordination: a parallel Appendix D on PR agent-intent#22 is the editor's
call on the environment.wallet_state side and is expected to land independently
on Douglas Borthwick's timing.

Co-Authored-By: Douglas Borthwick <256362537+douglasborthwick-crypto@users.noreply.github.com>
Signed-off-by: Michael Msebenzi <127877551+LembaGang@users.noreply.github.com>
LembaGang added a commit to LembaGang/verifiable-intent that referenced this pull request May 31, 2026
Stacked on v0.5.9-draft-d1-coverage-alignment (commit 486ae6d) which itself
stacks on v0.5.8 (0380ece) and v0.5.7 (21a156c). Applies six specific
corrections from Douglas's May 4 review of the v0.5.7-v0.5.9 stack and
his same-day follow-up tightening Fix agent-intent#5.

Scope of this revision:

- D.2 Organisation row corrected to "InsumerAPI (insumermodel.com)".
  InsumerAPI is the entity operating the environment.wallet_state issuer
  infrastructure (the RFC 6982 reference implementation D.2 documents),
  mirroring D.1's "Headless Oracle (headlessoracle.com)" pattern.
- §9 v0.5.7-draft row body updated correspondingly to reference
  "InsumerAPI (Douglas Borthwick)" rather than the prior wording that
  attributed the implementation to a different entity.
- D.2 Agent-native key provisioning row updated to "USDC/USDT/BTC
  on-chain payment". Production behaviour at POST /v1/keys/buy accepts
  USDC and USDT on EVM chains and Solana, plus BTC on Bitcoin, per
  Douglas's confirmation against PR agent-intent#22 v0.6.4 commit fc6d955 §7.4.
- §9 v0.5.8-draft and v0.5.9-draft row bodies updated to remove co-author
  attribution. Both patches were HO-side housekeeping with no Douglas
  input. The v0.5.8 and v0.5.9 commit message trailers were also
  dropped via amend+rebase in this sprint to align shipped state with
  what was committed to in correspondence. Only v0.5.7 (Appendix D
  listing both implementations as shared editorial work) warranted the
  co-author attribution and retains it.
- D.2 License row added between the existing Reference verifier row
  and the closing prose paragraph, mirroring D.1's License-row pattern,
  with final wording: "Proprietary. Copyright 2026 Douglas Borthwick."
  Two-sentence form is the cleaner default matching the posture across
  Douglas's other published surfaces; spec body does not carry patent-
  prosecution context where it would not serve standards-track readers.

Structural alignment between D.1 and D.2 (whether D.2 needs Operational
Since, Architectural rationale, or other rows mirroring D.1) is a
separate question and out of scope for v0.5.10.

This commit is the result of a stack rewrite that collapsed an earlier
v0.5.10 + v0.5.11 pair (where v0.5.11 added the License row tightening
on top of v0.5.10) into a single v0.5.10 commit with the License row
already at its final wording from the start. The collapse keeps
retracted-text quoting out of the changelog and commit-message prose
that working-group reviewers will read.

Document header stays at 0.5-draft; v0.5.10 is a patch-level refinement
stacked on v0.5.9 / v0.5.8 / v0.5.7 (not independent). No semantic
changes to spec body, no algorithm changes, no security-model changes,
no §4 schema changes, no Headless Oracle code changes required, test
count unchanged (1031+ baseline).

Co-Authored-By: Douglas Borthwick <256362537+douglasborthwick-crypto@users.noreply.github.com>
Signed-off-by: Michael Msebenzi <127877551+LembaGang@users.noreply.github.com>
LembaGang added a commit to LembaGang/verifiable-intent that referenced this pull request May 31, 2026
… + per-type)

Mirrors PR agent-intent#22 v0.6.5-draft commit 66185a1 (Douglas Borthwick, InsumerAPI).

Adds family-wide algorithm-deprecation prose to §4.7 mirroring
draft-borthwick-msebenzi-environment-state-00 v0.2-draft §4.3 family-wide
SHOULD ("Type specification authors SHOULD specify, in the type's
specification, a deprecation mechanism for the type's MUST-implement
algorithm before that algorithm is needed").

Adds per-type deprecation mechanism for environment.market_state:
conditions (NIST / IRTF CFRG / RFC 8032 / RFC 8725 update or cryptographic
break), timeline (>=12-month verifier-migration window from minor-version
revision publication; parallel verification during window; rejection after
window end), backward compatibility (mandate-issuer migration on key-
registry readiness; verifier detection via RFC 8615 well-known key-set
inspection at {issuer}/.well-known/oracle-keys.json).

Updates §4.7 PR agent-intent#22 coordination Note to reflect the family-wide algorithm-
deprecation discipline as co-equal with the agility framework, extension-set
model, and fail-closed-negotiation requirement.

Family-wide prose (algorithm-agnostic policy paragraph, single-algorithm
lock-in paragraph, family-wide deprecation paragraph) byte-identical to
PR agent-intent#22 §4.7.

Co-Authored-By: douglasborthwick-crypto <256362537+douglasborthwick-crypto@users.noreply.github.com>
Signed-off-by: Michael Msebenzi <127877551+LembaGang@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants