Remove non-protocol claims and make ledger optional

Move 6 metadata claims (pol_timestamp, inp_classification,
exec_time_ms, regulated_domain, model_version, witnessed_by)
from registered JWT claims to recommended ext extension keys.
Use short key names for spec-defined extensions.

Make audit ledger explicitly optional: rename pseudocode
parameter from ledger to ect_store, mark architecture diagram
ledger layer as optional, add conditional append logic, and
soften Audit Ledger Interface language.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-24 23:35:03 +01:00
parent d8d1524dac
commit 898b0f8747
4 changed files with 782 additions and 777 deletions

View File

@@ -1906,8 +1906,8 @@ between the identity layer and the application layer:<a href="#section-3.2-1" cl
|
v
+--------------------------------------------------+
| Ledger Layer (Immutable Record) |
| "All ECTs appended to audit ledger" |
| Optional: Audit Ledger (Immutable Record) |
| "ECTs MAY be appended to an audit ledger" |
+--------------------------------------------------+
</pre>
</div>
@@ -1978,7 +1978,8 @@ trust domain. WPT verification, if present, per
evaluated, and what precedent tasks exist.<a href="#section-3.3-7.2.1" class="pilcrow"></a></p>
</li>
<li id="section-3.3-7.3">
<p id="section-3.3-7.3.1">Ledger: Appends the verified ECT to the audit ledger.<a href="#section-3.3-7.3.1" class="pilcrow"></a></p>
<p id="section-3.3-7.3.1">Ledger (if deployed): Appends the verified ECT to the audit
ledger.<a href="#section-3.3-7.3.1" class="pilcrow"></a></p>
</li>
</ol>
</section>
@@ -2329,42 +2330,41 @@ that do not understand extension claims <span class="bcp14">MUST</span> ignore t
<dd class="break"></dd>
</dl>
<p id="section-4.2.6-2">To avoid key collisions between different domains, extension
key names <span class="bcp14">MUST</span> use reverse domain notation (e.g.,
"com.example.custom_field"). Implementations <span class="bcp14">MUST NOT</span> use
unqualified key names within the "ext" object. To prevent
abuse and excessive token size, the serialized JSON
representation of the "ext" object <span class="bcp14">SHOULD NOT</span> exceed 4096
bytes, and the JSON nesting depth within the "ext" object
<span class="bcp14">SHOULD NOT</span> exceed 5 levels. Implementations <span class="bcp14">SHOULD</span> reject
ECTs whose "ext" claim exceeds these limits.<a href="#section-4.2.6-2" class="pilcrow"></a></p>
<p id="section-4.2.6-3">The following extension keys are <span class="bcp14">RECOMMENDED</span> for common use
cases. These are not registered claims; they are carried
within the "ext" object:<a href="#section-4.2.6-3" class="pilcrow"></a></p>
key names <span class="bcp14">SHOULD</span> use reverse domain notation (e.g.,
"com.example.custom_field") to avoid collisions between
independently developed extensions. To prevent abuse and
excessive token size, the serialized JSON representation of
the "ext" object <span class="bcp14">SHOULD NOT</span> exceed 4096 bytes, and the JSON
nesting depth within the "ext" object <span class="bcp14">SHOULD NOT</span> exceed 5
levels. Implementations <span class="bcp14">SHOULD</span> reject ECTs whose "ext" claim
exceeds these limits.<a href="#section-4.2.6-2" class="pilcrow"></a></p>
<p id="section-4.2.6-3">The following extension keys are defined by this specification
for common use cases. Because these keys are documented here,
they use short names without reverse domain prefixes:<a href="#section-4.2.6-3" class="pilcrow"></a></p>
<ul class="normal">
<li class="normal" id="section-4.2.6-4.1">
<p id="section-4.2.6-4.1.1">"org.ietf.wimse.exec_time_ms": Integer. Execution duration in
milliseconds.<a href="#section-4.2.6-4.1.1" class="pilcrow"></a></p>
<p id="section-4.2.6-4.1.1">"exec_time_ms": Integer. Execution duration in milliseconds.<a href="#section-4.2.6-4.1.1" class="pilcrow"></a></p>
</li>
<li class="normal" id="section-4.2.6-4.2">
<p id="section-4.2.6-4.2.1">"org.ietf.wimse.regulated_domain": String. Regulatory domain
(e.g., "medtech", "finance", "military").<a href="#section-4.2.6-4.2.1" class="pilcrow"></a></p>
<p id="section-4.2.6-4.2.1">"regulated_domain": String. Regulatory domain (e.g.,
"medtech", "finance", "military").<a href="#section-4.2.6-4.2.1" class="pilcrow"></a></p>
</li>
<li class="normal" id="section-4.2.6-4.3">
<p id="section-4.2.6-4.3.1">"org.ietf.wimse.model_version": String. AI/ML model version.<a href="#section-4.2.6-4.3.1" class="pilcrow"></a></p>
<p id="section-4.2.6-4.3.1">"model_version": String. AI/ML model version.<a href="#section-4.2.6-4.3.1" class="pilcrow"></a></p>
</li>
<li class="normal" id="section-4.2.6-4.4">
<p id="section-4.2.6-4.4.1">"org.ietf.wimse.witnessed_by": Array of StringOrURI. Identifiers
of third-party entities that the issuer claims observed the
<p id="section-4.2.6-4.4.1">"witnessed_by": Array of StringOrURI. Identifiers of
third-party entities that the issuer claims observed the
task. Note: this is self-asserted; for verifiable witness
attestation, witnesses should submit independent signed ECTs.<a href="#section-4.2.6-4.4.1" class="pilcrow"></a></p>
</li>
<li class="normal" id="section-4.2.6-4.5">
<p id="section-4.2.6-4.5.1">"org.ietf.wimse.inp_classification": String. Data sensitivity
classification (e.g., "public", "confidential", "restricted").<a href="#section-4.2.6-4.5.1" class="pilcrow"></a></p>
<p id="section-4.2.6-4.5.1">"inp_classification": String. Data sensitivity classification
(e.g., "public", "confidential", "restricted").<a href="#section-4.2.6-4.5.1" class="pilcrow"></a></p>
</li>
<li class="normal" id="section-4.2.6-4.6">
<p id="section-4.2.6-4.6.1">"org.ietf.wimse.pol_timestamp": NumericDate. Time at which the
policy decision was made, if distinct from "iat".<a href="#section-4.2.6-4.6.1" class="pilcrow"></a></p>
<p id="section-4.2.6-4.6.1">"pol_timestamp": NumericDate. Time at which the policy
decision was made, if distinct from "iat".<a href="#section-4.2.6-4.6.1" class="pilcrow"></a></p>
</li>
</ul>
</section>
@@ -2401,10 +2401,10 @@ policy decision was made, if distinct from "iat".<a href="#section-4.2.6-4.6.1"
"out_hash": "sha-256:LCa0a2j_xo_5m0U8HTBBNBNCLXBkg7-g-YpeiGJm564",
"ext": {
"org.ietf.wimse.pol_timestamp": 1772064145,
"org.ietf.wimse.exec_time_ms": 245,
"org.ietf.wimse.regulated_domain": "medtech",
"org.ietf.wimse.model_version": "clinical-reasoning-v4.2"
"pol_timestamp": 1772064145,
"exec_time_ms": 245,
"regulated_domain": "medtech",
"model_version": "clinical-reasoning-v4.2"
}
}
</pre>
@@ -2479,8 +2479,8 @@ provides a cryptographically signed record of execution ordering,
enabling auditors to reconstruct the complete workflow and verify
that required predecessor tasks were recorded before dependent
tasks.<a href="#section-6.1-1" class="pilcrow"></a></p>
<p id="section-6.1-2">DAG validation is performed against the audit ledger, which
serves as the authoritative store of previously verified ECTs.<a href="#section-6.1-2" class="pilcrow"></a></p>
<p id="section-6.1-2">DAG validation is performed against the ECT store — either an
audit ledger or the set of parent ECTs received inline.<a href="#section-6.1-2" class="pilcrow"></a></p>
</section>
</div>
<div id="validation-rules">
@@ -2549,14 +2549,14 @@ relationship has been established.<a href="#section-6.2-2.6.1" class="pilcrow">
<figure id="figure-6">
<div class="lang-pseudocode sourcecode" id="section-6.3-2.1">
<pre>
function validate_dag(ect, ledger, clock_skew_tolerance):
function validate_dag(ect, ect_store, clock_skew_tolerance):
// Step 1: Uniqueness check
if ledger.contains(ect.jti, ect.wid):
if ect_store.contains(ect.jti, ect.wid):
return error("ECT ID already exists")
// Step 2: Parent existence and temporal ordering
for parent_id in ect.par:
parent = ledger.get(parent_id)
parent = ect_store.get(parent_id)
if parent is null:
return error("Parent task not found: " + parent_id)
if parent.iat &gt;= ect.iat + clock_skew_tolerance:
@@ -2564,14 +2564,14 @@ function validate_dag(ect, ledger, clock_skew_tolerance):
// Step 3: Cycle detection (with traversal limit)
visited = set()
result = has_cycle(ect.jti, ect.par, ledger, visited,
result = has_cycle(ect.jti, ect.par, ect_store, visited,
max_ancestor_limit)
if result is error or result is true:
return error("Circular dependency or depth limit exceeded")
return success
function has_cycle(target_jti, parent_ids, ledger,
function has_cycle(target_jti, parent_ids, ect_store,
visited, max_depth):
if visited.size() &gt;= max_depth:
return error("Maximum ancestor traversal limit exceeded")
@@ -2581,9 +2581,9 @@ function has_cycle(target_jti, parent_ids, ledger,
if parent_id in visited:
continue
visited.add(parent_id)
parent = ledger.get(parent_id)
parent = ect_store.get(parent_id)
if parent is not null:
result = has_cycle(target_jti, parent.par, ledger,
result = has_cycle(target_jti, parent.par, ect_store,
visited, max_depth)
if result is error or result is true:
return result
@@ -2714,7 +2714,7 @@ fails.<a href="#section-7.1-4" class="pilcrow">¶</a></p>
<div class="breakable lang-pseudocode sourcecode" id="section-7.2-1.1">
<pre>
function verify_ect(ect_jws, verifier_id,
trust_domain_keys, ledger):
trust_domain_keys, ect_store):
// Parse JWS
(header, payload, signature) = parse_jws(ect_jws)
@@ -2775,14 +2775,15 @@ function verify_ect(ect_jws, verifier_id,
["approved", "rejected", "pending_human_review"]:
return reject("Invalid pol_decision value")
// Validate DAG (against ledger or inline parent ECTs)
result = validate_dag(payload, ledger,
// Validate DAG (against ECT store or inline parent ECTs)
result = validate_dag(payload, ect_store,
clock_skew_tolerance)
if result is error:
return reject("DAG validation failed")
// All checks passed; append to ledger
ledger.append(payload)
// All checks passed; record if store is available
if ect_store is not null:
ect_store.append(payload)
return accept
</pre>
</div>
@@ -2799,14 +2800,14 @@ function verify_ect(ect_jws, verifier_id,
<h2 id="name-audit-ledger-interface">
<a href="#section-8" class="section-number selfRef">8. </a><a href="#name-audit-ledger-interface" class="section-name selfRef">Audit Ledger Interface</a>
</h2>
<p id="section-8-1">ECTs are designed to be recorded in an immutable audit ledger for
compliance verification and post-hoc analysis. This specification
defines required properties for the ledger but does not mandate
a specific storage technology. Implementations <span class="bcp14">MAY</span> use
append-only logs, databases with cryptographic commitment schemes,
distributed ledgers, or any storage mechanism that provides the
required properties.<a href="#section-8-1" class="pilcrow"></a></p>
<p id="section-8-2">An audit ledger implementation <span class="bcp14">MUST</span> provide:<a href="#section-8-2" class="pilcrow"></a></p>
<p id="section-8-1">ECTs <span class="bcp14">MAY</span> be recorded in an immutable audit ledger for compliance
verification and post-hoc analysis. A ledger is <span class="bcp14">RECOMMENDED</span> for
regulated environments but is not required for point-to-point
operation. This specification does not mandate a specific storage
technology. Implementations <span class="bcp14">MAY</span> use append-only logs, databases
with cryptographic commitment schemes, distributed ledgers, or
any storage mechanism that provides the required properties.<a href="#section-8-1" class="pilcrow"></a></p>
<p id="section-8-2">When an audit ledger is deployed, the implementation <span class="bcp14">MUST</span> provide:<a href="#section-8-2" class="pilcrow"></a></p>
<ol start="1" type="1" class="normal type-1" id="section-8-3">
<li id="section-8-3.1">
<p id="section-8-3.1.1">Append-only semantics: Once an ECT is recorded, it <span class="bcp14">MUST NOT</span> be
@@ -2883,7 +2884,7 @@ Human Release Manager:
exec_act: approve_release
pol: release_approval_policy pol_decision: approved
pol_enforcer: spiffe://meddev.example/human/release-mgr-42
ext: {org.ietf.wimse.witnessed_by: [...]} (extension metadata)
ext: {witnessed_by: [...]} (extension metadata)
</pre>
</div>
<figcaption><a href="#figure-8" class="selfRef">Figure 8</a>:
@@ -3167,7 +3168,7 @@ evaluating the policy).<a href="#section-10.2-1" class="pilcrow">¶</a></p>
</ul>
<p id="section-10.2-4">The trustworthiness of ECT claims depends on the trustworthiness
of the signing agent. To mitigate single-agent false claims,
regulated environments <span class="bcp14">SHOULD</span> use the "org.ietf.wimse.witnessed_by"
regulated environments <span class="bcp14">SHOULD</span> use the "witnessed_by"
extension key (carried in "ext") to include independent
third-party observers at critical decision points. However,
this value is self-asserted by the ECT issuer: the listed
@@ -3181,7 +3182,7 @@ did not participate.<a href="#section-10.2-4" class="pilcrow">¶</a></p>
<a href="#section-10.2.1" class="section-number selfRef">10.2.1. </a><a href="#name-witness-attestation-model" class="section-name selfRef">Witness Attestation Model</a>
</h4>
<p id="section-10.2.1-1">To address the self-assertion limitation of the
"org.ietf.wimse.witnessed_by" extension, witnesses <span class="bcp14">SHOULD</span> submit their
"witnessed_by" extension, witnesses <span class="bcp14">SHOULD</span> submit their
own independent signed ECTs to the audit ledger attesting to the
observed task. A witness attestation ECT:<a href="#section-10.2.1-1" class="pilcrow"></a></p>
<ul class="normal">
@@ -3201,7 +3202,7 @@ linking the attestation to the original task.<a href="#section-10.2.1-2.3.1" cla
confirms the observation.<a href="#section-10.2.1-2.4.1" class="pilcrow"></a></p>
</li>
</ul>
<p id="section-10.2.1-3">When a task's "org.ietf.wimse.witnessed_by" extension lists one or more
<p id="section-10.2.1-3">When a task's "witnessed_by" extension lists one or more
witnesses, auditors <span class="bcp14">SHOULD</span> verify that corresponding witness
attestation ECTs exist in the ledger for each listed witness. A
mismatch between the extension value and the set of independent
@@ -3353,7 +3354,7 @@ create a false execution history if they control the ledger.<a href="#section-10
by an entity independent of the workflow agents.<a href="#section-10.8-3.1.1" class="pilcrow"></a></p>
</li>
<li class="normal" id="section-10.8-3.2">
<p id="section-10.8-3.2.1">Witness attestation: Using the "org.ietf.wimse.witnessed_by" extension
<p id="section-10.8-3.2.1">Witness attestation: Using the "witnessed_by" extension
key in "ext" to include independent third-party observers.<a href="#section-10.8-3.2.1" class="pilcrow"></a></p>
</li>
<li class="normal" id="section-10.8-3.3">
@@ -4412,7 +4413,7 @@ autonomous agents and human release approval:<a href="#appendix-D.2-1" class="pi
"pol_decision": "approved",
"pol_enforcer": "spiffe://meddev.example/human/release-mgr-42",
"ext": {
"org.ietf.wimse.witnessed_by": [
"witnessed_by": [
"spiffe://meddev.example/audit/qa-observer-1"
]
}
@@ -4423,7 +4424,7 @@ autonomous agents and human release approval:<a href="#appendix-D.2-1" class="pi
implementation, implementation preceded testing, testing preceded
build, and a human release manager approved the final release.
The "ext" object in task 5 carries witness metadata via
the "org.ietf.wimse.witnessed_by" extension key.<a href="#appendix-D.2-12" class="pilcrow"></a></p>
the "witnessed_by" extension key.<a href="#appendix-D.2-12" class="pilcrow"></a></p>
<div class="alignLeft art-text artwork" id="appendix-D.2-13">
<pre>
task-...-0001 (review_requirements_spec)

View File

@@ -292,8 +292,8 @@ between the identity layer and the application layer:
|
v
+--------------------------------------------------+
| Ledger Layer (Immutable Record) |
| "All ECTs appended to audit ledger" |
| Optional: Audit Ledger (Immutable Record) |
| "ECTs MAY be appended to an audit ledger" |
+--------------------------------------------------+
~~~
{: #fig-layers title="WIMSE Extension Architecture Layers"}
@@ -345,7 +345,8 @@ The receiving agent (Agent B) verifies in order:
2. ECT (this extension): Records what Agent A did, what policy was
evaluated, and what precedent tasks exist.
3. Ledger: Appends the verified ECT to the audit ledger.
3. Ledger (if deployed): Appends the verified ECT to the audit
ledger.
# Execution Context Token Format {#ect-format}
@@ -592,32 +593,31 @@ ext:
that do not understand extension claims MUST ignore them.
To avoid key collisions between different domains, extension
key names MUST use reverse domain notation (e.g.,
"com.example.custom_field"). Implementations MUST NOT use
unqualified key names within the "ext" object. To prevent
abuse and excessive token size, the serialized JSON
representation of the "ext" object SHOULD NOT exceed 4096
bytes, and the JSON nesting depth within the "ext" object
SHOULD NOT exceed 5 levels. Implementations SHOULD reject
ECTs whose "ext" claim exceeds these limits.
key names SHOULD use reverse domain notation (e.g.,
"com.example.custom_field") to avoid collisions between
independently developed extensions. To prevent abuse and
excessive token size, the serialized JSON representation of
the "ext" object SHOULD NOT exceed 4096 bytes, and the JSON
nesting depth within the "ext" object SHOULD NOT exceed 5
levels. Implementations SHOULD reject ECTs whose "ext" claim
exceeds these limits.
The following extension keys are RECOMMENDED for common use
cases. These are not registered claims; they are carried
within the "ext" object:
The following extension keys are defined by this specification
for common use cases. Because these keys are documented here,
they use short names without reverse domain prefixes:
- "org.ietf.wimse.exec\_time\_ms": Integer. Execution duration in
milliseconds.
- "org.ietf.wimse.regulated\_domain": String. Regulatory domain
(e.g., "medtech", "finance", "military").
- "org.ietf.wimse.model\_version": String. AI/ML model version.
- "org.ietf.wimse.witnessed\_by": Array of StringOrURI. Identifiers
of third-party entities that the issuer claims observed the
- "exec\_time\_ms": Integer. Execution duration in milliseconds.
- "regulated\_domain": String. Regulatory domain (e.g.,
"medtech", "finance", "military").
- "model\_version": String. AI/ML model version.
- "witnessed\_by": Array of StringOrURI. Identifiers of
third-party entities that the issuer claims observed the
task. Note: this is self-asserted; for verifiable witness
attestation, witnesses should submit independent signed ECTs.
- "org.ietf.wimse.inp\_classification": String. Data sensitivity
classification (e.g., "public", "confidential", "restricted").
- "org.ietf.wimse.pol\_timestamp": NumericDate. Time at which the
policy decision was made, if distinct from "iat".
- "inp\_classification": String. Data sensitivity classification
(e.g., "public", "confidential", "restricted").
- "pol\_timestamp": NumericDate. Time at which the policy
decision was made, if distinct from "iat".
## Complete ECT Example
@@ -644,10 +644,10 @@ The following is a complete ECT payload example:
"out_hash": "sha-256:LCa0a2j_xo_5m0U8HTBBNBNCLXBkg7-g-YpeiGJm564",
"ext": {
"org.ietf.wimse.pol_timestamp": 1772064145,
"org.ietf.wimse.exec_time_ms": 245,
"org.ietf.wimse.regulated_domain": "medtech",
"org.ietf.wimse.model_version": "clinical-reasoning-v4.2"
"pol_timestamp": 1772064145,
"exec_time_ms": 245,
"regulated_domain": "medtech",
"model_version": "clinical-reasoning-v4.2"
}
}
~~~
@@ -699,8 +699,8 @@ enabling auditors to reconstruct the complete workflow and verify
that required predecessor tasks were recorded before dependent
tasks.
DAG validation is performed against the audit ledger, which
serves as the authoritative store of previously verified ECTs.
DAG validation is performed against the ECT store — either an
audit ledger or the set of parent ECTs received inline.
## Validation Rules
@@ -752,14 +752,14 @@ the following DAG validation steps:
The following pseudocode describes the DAG validation procedure:
~~~ pseudocode
function validate_dag(ect, ledger, clock_skew_tolerance):
function validate_dag(ect, ect_store, clock_skew_tolerance):
// Step 1: Uniqueness check
if ledger.contains(ect.jti, ect.wid):
if ect_store.contains(ect.jti, ect.wid):
return error("ECT ID already exists")
// Step 2: Parent existence and temporal ordering
for parent_id in ect.par:
parent = ledger.get(parent_id)
parent = ect_store.get(parent_id)
if parent is null:
return error("Parent task not found: " + parent_id)
if parent.iat >= ect.iat + clock_skew_tolerance:
@@ -767,14 +767,14 @@ function validate_dag(ect, ledger, clock_skew_tolerance):
// Step 3: Cycle detection (with traversal limit)
visited = set()
result = has_cycle(ect.jti, ect.par, ledger, visited,
result = has_cycle(ect.jti, ect.par, ect_store, visited,
max_ancestor_limit)
if result is error or result is true:
return error("Circular dependency or depth limit exceeded")
return success
function has_cycle(target_jti, parent_ids, ledger,
function has_cycle(target_jti, parent_ids, ect_store,
visited, max_depth):
if visited.size() >= max_depth:
return error("Maximum ancestor traversal limit exceeded")
@@ -784,9 +784,9 @@ function has_cycle(target_jti, parent_ids, ledger,
if parent_id in visited:
continue
visited.add(parent_id)
parent = ledger.get(parent_id)
parent = ect_store.get(parent_id)
if parent is not null:
result = has_cycle(target_jti, parent.par, ledger,
result = has_cycle(target_jti, parent.par, ect_store,
visited, max_depth)
if result is error or result is true:
return result
@@ -883,7 +883,7 @@ fails.
~~~ pseudocode
function verify_ect(ect_jws, verifier_id,
trust_domain_keys, ledger):
trust_domain_keys, ect_store):
// Parse JWS
(header, payload, signature) = parse_jws(ect_jws)
@@ -944,29 +944,30 @@ function verify_ect(ect_jws, verifier_id,
["approved", "rejected", "pending_human_review"]:
return reject("Invalid pol_decision value")
// Validate DAG (against ledger or inline parent ECTs)
result = validate_dag(payload, ledger,
// Validate DAG (against ECT store or inline parent ECTs)
result = validate_dag(payload, ect_store,
clock_skew_tolerance)
if result is error:
return reject("DAG validation failed")
// All checks passed; append to ledger
ledger.append(payload)
// All checks passed; record if store is available
if ect_store is not null:
ect_store.append(payload)
return accept
~~~
{: #fig-verification title="ECT Verification Pseudocode"}
# Audit Ledger Interface {#ledger-interface}
ECTs are designed to be recorded in an immutable audit ledger for
compliance verification and post-hoc analysis. This specification
defines required properties for the ledger but does not mandate
a specific storage technology. Implementations MAY use
append-only logs, databases with cryptographic commitment schemes,
distributed ledgers, or any storage mechanism that provides the
required properties.
ECTs MAY be recorded in an immutable audit ledger for compliance
verification and post-hoc analysis. A ledger is RECOMMENDED for
regulated environments but is not required for point-to-point
operation. This specification does not mandate a specific storage
technology. Implementations MAY use append-only logs, databases
with cryptographic commitment schemes, distributed ledgers, or
any storage mechanism that provides the required properties.
An audit ledger implementation MUST provide:
When an audit ledger is deployed, the implementation MUST provide:
1. Append-only semantics: Once an ECT is recorded, it MUST NOT be
modified or deleted.
@@ -1031,7 +1032,7 @@ Human Release Manager:
exec_act: approve_release
pol: release_approval_policy pol_decision: approved
pol_enforcer: spiffe://meddev.example/human/release-mgr-42
ext: {org.ietf.wimse.witnessed_by: [...]} (extension metadata)
ext: {witnessed_by: [...]} (extension metadata)
~~~
{: #fig-medtech-sdlc title="Medical Device SDLC Workflow"}
@@ -1222,7 +1223,7 @@ ECTs do not independently verify that:
The trustworthiness of ECT claims depends on the trustworthiness
of the signing agent. To mitigate single-agent false claims,
regulated environments SHOULD use the "org.ietf.wimse.witnessed_by"
regulated environments SHOULD use the "witnessed_by"
extension key (carried in "ext") to include independent
third-party observers at critical decision points. However,
this value is self-asserted by the ECT issuer: the listed
@@ -1234,7 +1235,7 @@ did not participate.
### Witness Attestation Model {#witness-attestation-model}
To address the self-assertion limitation of the
"org.ietf.wimse.witnessed_by" extension, witnesses SHOULD submit their
"witnessed_by" extension, witnesses SHOULD submit their
own independent signed ECTs to the audit ledger attesting to the
observed task. A witness attestation ECT:
@@ -1246,7 +1247,7 @@ observed task. A witness attestation ECT:
- MUST set "pol_decision" to "approved" to indicate the witness
confirms the observation.
When a task's "org.ietf.wimse.witnessed_by" extension lists one or more
When a task's "witnessed_by" extension lists one or more
witnesses, auditors SHOULD verify that corresponding witness
attestation ECTs exist in the ledger for each listed witness. A
mismatch between the extension value and the set of independent
@@ -1352,7 +1353,7 @@ Mitigations include:
- Independent ledger maintenance: The ledger SHOULD be maintained
by an entity independent of the workflow agents.
- Witness attestation: Using the "org.ietf.wimse.witnessed_by" extension
- Witness attestation: Using the "witnessed_by" extension
key in "ext" to include independent third-party observers.
- Cross-verification: Multiple independent ledger replicas can be
compared for consistency.
@@ -1927,7 +1928,7 @@ Task 5 (Human Release Manager Approval):
"pol_decision": "approved",
"pol_enforcer": "spiffe://meddev.example/human/release-mgr-42",
"ext": {
"org.ietf.wimse.witnessed_by": [
"witnessed_by": [
"spiffe://meddev.example/audit/qa-observer-1"
]
}
@@ -1938,7 +1939,7 @@ The resulting DAG records the complete SDLC: spec review preceded
implementation, implementation preceded testing, testing preceded
build, and a human release manager approved the final release.
The "ext" object in task 5 carries witness metadata via
the "org.ietf.wimse.witnessed_by" extension key.
the "witnessed_by" extension key.
~~~
task-...-0001 (review_requirements_spec)

View File

@@ -409,8 +409,8 @@ Internet-Draft WIMSE Execution Context February 2026
|
v
+--------------------------------------------------+
| Ledger Layer (Immutable Record) |
| "All ECTs appended to audit ledger" |
| Optional: Audit Ledger (Immutable Record) |
| "ECTs MAY be appended to an audit ledger" |
+--------------------------------------------------+
Figure 1: WIMSE Extension Architecture Layers
@@ -466,7 +466,8 @@ Internet-Draft WIMSE Execution Context February 2026
2. ECT (this extension): Records what Agent A did, what policy was
evaluated, and what precedent tasks exist.
3. Ledger: Appends the verified ECT to the audit ledger.
3. Ledger (if deployed): Appends the verified ECT to the audit
ledger.
4. Execution Context Token Format
@@ -497,7 +498,6 @@ Internet-Draft WIMSE Execution Context February 2026
from other JWT types, consistent with the WIMSE convention for
type parameter values.
kid: REQUIRED. The key identifier referencing the public key from
@@ -506,6 +506,7 @@ Nennemann Expires 28 August 2026 [Page 9]
Internet-Draft WIMSE Execution Context February 2026
kid: REQUIRED. The key identifier referencing the public key from
the agent's WIT [RFC7517]. Used by verifiers to look up the
correct public key for signature verification.
@@ -556,7 +557,6 @@ Internet-Draft WIMSE Execution Context February 2026
Nennemann Expires 28 August 2026 [Page 10]
Internet-Draft WIMSE Execution Context February 2026
@@ -734,36 +734,35 @@ Internet-Draft WIMSE Execution Context February 2026
not understand extension claims MUST ignore them.
To avoid key collisions between different domains, extension key
names MUST use reverse domain notation (e.g.,
"com.example.custom_field"). Implementations MUST NOT use
unqualified key names within the "ext" object. To prevent abuse and
excessive token size, the serialized JSON representation of the "ext"
object SHOULD NOT exceed 4096 bytes, and the JSON nesting depth
within the "ext" object SHOULD NOT exceed 5 levels. Implementations
SHOULD reject ECTs whose "ext" claim exceeds these limits.
names SHOULD use reverse domain notation (e.g.,
"com.example.custom_field") to avoid collisions between independently
developed extensions. To prevent abuse and excessive token size, the
serialized JSON representation of the "ext" object SHOULD NOT exceed
4096 bytes, and the JSON nesting depth within the "ext" object SHOULD
NOT exceed 5 levels. Implementations SHOULD reject ECTs whose "ext"
claim exceeds these limits.
The following extension keys are RECOMMENDED for common use cases.
These are not registered claims; they are carried within the "ext"
object:
The following extension keys are defined by this specification for
common use cases. Because these keys are documented here, they use
short names without reverse domain prefixes:
* "org.ietf.wimse.exec_time_ms": Integer. Execution duration in
milliseconds.
* "exec_time_ms": Integer. Execution duration in milliseconds.
* "org.ietf.wimse.regulated_domain": String. Regulatory domain
(e.g., "medtech", "finance", "military").
* "regulated_domain": String. Regulatory domain (e.g., "medtech",
"finance", "military").
* "org.ietf.wimse.model_version": String. AI/ML model version.
* "model_version": String. AI/ML model version.
* "org.ietf.wimse.witnessed_by": Array of StringOrURI. Identifiers
of third-party entities that the issuer claims observed the task.
Note: this is self-asserted; for verifiable witness attestation,
witnesses should submit independent signed ECTs.
* "witnessed_by": Array of StringOrURI. Identifiers of third-party
entities that the issuer claims observed the task. Note: this is
self-asserted; for verifiable witness attestation, witnesses
should submit independent signed ECTs.
* "org.ietf.wimse.inp_classification": String. Data sensitivity
classification (e.g., "public", "confidential", "restricted").
* "inp_classification": String. Data sensitivity classification
(e.g., "public", "confidential", "restricted").
* "org.ietf.wimse.pol_timestamp": NumericDate. Time at which the
policy decision was made, if distinct from "iat".
* "pol_timestamp": NumericDate. Time at which the policy decision
was made, if distinct from "iat".
4.3. Complete ECT Example
@@ -781,6 +780,7 @@ Internet-Draft WIMSE Execution Context February 2026
Nennemann Expires 28 August 2026 [Page 14]
Internet-Draft WIMSE Execution Context February 2026
@@ -806,10 +806,10 @@ Internet-Draft WIMSE Execution Context February 2026
"out_hash": "sha-256:LCa0a2j_xo_5m0U8HTBBNBNCLXBkg7-g-YpeiGJm564",
"ext": {
"org.ietf.wimse.pol_timestamp": 1772064145,
"org.ietf.wimse.exec_time_ms": 245,
"org.ietf.wimse.regulated_domain": "medtech",
"org.ietf.wimse.model_version": "clinical-reasoning-v4.2"
"pol_timestamp": 1772064145,
"exec_time_ms": 245,
"regulated_domain": "medtech",
"model_version": "clinical-reasoning-v4.2"
}
}
@@ -865,8 +865,8 @@ Internet-Draft WIMSE Execution Context February 2026
auditors to reconstruct the complete workflow and verify that
required predecessor tasks were recorded before dependent tasks.
DAG validation is performed against the audit ledger, which serves as
the authoritative store of previously verified ECTs.
DAG validation is performed against the ECT store — either an audit
ledger or the set of parent ECTs received inline.
6.2. Validation Rules
@@ -954,14 +954,14 @@ Nennemann Expires 28 August 2026 [Page 17]
Internet-Draft WIMSE Execution Context February 2026
function validate_dag(ect, ledger, clock_skew_tolerance):
function validate_dag(ect, ect_store, clock_skew_tolerance):
// Step 1: Uniqueness check
if ledger.contains(ect.jti, ect.wid):
if ect_store.contains(ect.jti, ect.wid):
return error("ECT ID already exists")
// Step 2: Parent existence and temporal ordering
for parent_id in ect.par:
parent = ledger.get(parent_id)
parent = ect_store.get(parent_id)
if parent is null:
return error("Parent task not found: " + parent_id)
if parent.iat >= ect.iat + clock_skew_tolerance:
@@ -969,14 +969,14 @@ Internet-Draft WIMSE Execution Context February 2026
// Step 3: Cycle detection (with traversal limit)
visited = set()
result = has_cycle(ect.jti, ect.par, ledger, visited,
result = has_cycle(ect.jti, ect.par, ect_store, visited,
max_ancestor_limit)
if result is error or result is true:
return error("Circular dependency or depth limit exceeded")
return success
function has_cycle(target_jti, parent_ids, ledger,
function has_cycle(target_jti, parent_ids, ect_store,
visited, max_depth):
if visited.size() >= max_depth:
return error("Maximum ancestor traversal limit exceeded")
@@ -986,9 +986,9 @@ Internet-Draft WIMSE Execution Context February 2026
if parent_id in visited:
continue
visited.add(parent_id)
parent = ledger.get(parent_id)
parent = ect_store.get(parent_id)
if parent is not null:
result = has_cycle(target_jti, parent.par, ledger,
result = has_cycle(target_jti, parent.par, ect_store,
visited, max_depth)
if result is error or result is true:
return result
@@ -1100,7 +1100,7 @@ Internet-Draft WIMSE Execution Context February 2026
7.2. Verification Pseudocode
function verify_ect(ect_jws, verifier_id,
trust_domain_keys, ledger):
trust_domain_keys, ect_store):
// Parse JWS
(header, payload, signature) = parse_jws(ect_jws)
@@ -1169,7 +1169,7 @@ Internet-Draft WIMSE Execution Context February 2026
["approved", "rejected", "pending_human_review"]:
return reject("Invalid pol_decision value")
// Validate DAG (against ledger or inline parent ECTs)
// Validate DAG (against ECT store or inline parent ECTs)
@@ -1178,28 +1178,29 @@ Nennemann Expires 28 August 2026 [Page 21]
Internet-Draft WIMSE Execution Context February 2026
result = validate_dag(payload, ledger,
result = validate_dag(payload, ect_store,
clock_skew_tolerance)
if result is error:
return reject("DAG validation failed")
// All checks passed; append to ledger
ledger.append(payload)
// All checks passed; record if store is available
if ect_store is not null:
ect_store.append(payload)
return accept
Figure 7: ECT Verification Pseudocode
8. Audit Ledger Interface
ECTs are designed to be recorded in an immutable audit ledger for
compliance verification and post-hoc analysis. This specification
defines required properties for the ledger but does not mandate a
specific storage technology. Implementations MAY use append-only
logs, databases with cryptographic commitment schemes, distributed
ledgers, or any storage mechanism that provides the required
properties.
ECTs MAY be recorded in an immutable audit ledger for compliance
verification and post-hoc analysis. A ledger is RECOMMENDED for
regulated environments but is not required for point-to-point
operation. This specification does not mandate a specific storage
technology. Implementations MAY use append-only logs, databases with
cryptographic commitment schemes, distributed ledgers, or any storage
mechanism that provides the required properties.
An audit ledger implementation MUST provide:
When an audit ledger is deployed, the implementation MUST provide:
1. Append-only semantics: Once an ECT is recorded, it MUST NOT be
modified or deleted.
@@ -1228,7 +1229,6 @@ Internet-Draft WIMSE Execution Context February 2026
Nennemann Expires 28 August 2026 [Page 22]
Internet-Draft WIMSE Execution Context February 2026
@@ -1271,7 +1271,7 @@ Internet-Draft WIMSE Execution Context February 2026
exec_act: approve_release
pol: release_approval_policy pol_decision: approved
pol_enforcer: spiffe://meddev.example/human/release-mgr-42
ext: {org.ietf.wimse.witnessed_by: [...]} (extension metadata)
ext: {witnessed_by: [...]} (extension metadata)
Figure 8: Medical Device SDLC Workflow
@@ -1536,20 +1536,20 @@ Internet-Draft WIMSE Execution Context February 2026
The trustworthiness of ECT claims depends on the trustworthiness of
the signing agent. To mitigate single-agent false claims, regulated
environments SHOULD use the "org.ietf.wimse.witnessed_by" extension
key (carried in "ext") to include independent third-party observers
at critical decision points. However, this value is self-asserted by
the ECT issuer: the listed witnesses do not co-sign the ECT and there
is no cryptographic evidence within a single ECT that the witnesses
environments SHOULD use the "witnessed_by" extension key (carried in
"ext") to include independent third-party observers at critical
decision points. However, this value is self-asserted by the ECT
issuer: the listed witnesses do not co-sign the ECT and there is no
cryptographic evidence within a single ECT that the witnesses
actually observed the task. An issuing agent could list witnesses
that did not participate.
10.2.1. Witness Attestation Model
To address the self-assertion limitation of the
"org.ietf.wimse.witnessed_by" extension, witnesses SHOULD submit
their own independent signed ECTs to the audit ledger attesting to
the observed task. A witness attestation ECT:
To address the self-assertion limitation of the "witnessed_by"
extension, witnesses SHOULD submit their own independent signed ECTs
to the audit ledger attesting to the observed task. A witness
attestation ECT:
* MUST set "iss" to the witness's own workload identity.
@@ -1570,11 +1570,11 @@ Nennemann Expires 28 August 2026 [Page 28]
Internet-Draft WIMSE Execution Context February 2026
When a task's "org.ietf.wimse.witnessed_by" extension lists one or
more witnesses, auditors SHOULD verify that corresponding witness
attestation ECTs exist in the ledger for each listed witness. A
mismatch between the extension value and the set of independent
witness ECTs in the ledger SHOULD be flagged during audit review.
When a task's "witnessed_by" extension lists one or more witnesses,
auditors SHOULD verify that corresponding witness attestation ECTs
exist in the ledger for each listed witness. A mismatch between the
extension value and the set of independent witness ECTs in the ledger
SHOULD be flagged during audit review.
This model converts witness attestation from a self-asserted claim to
a cryptographically verifiable property of the ledger: the witness
@@ -1702,9 +1702,8 @@ Internet-Draft WIMSE Execution Context February 2026
* Independent ledger maintenance: The ledger SHOULD be maintained by
an entity independent of the workflow agents.
* Witness attestation: Using the "org.ietf.wimse.witnessed_by"
extension key in "ext" to include independent third-party
observers.
* Witness attestation: Using the "witnessed_by" extension key in
"ext" to include independent third-party observers.
* Cross-verification: Multiple independent ledger replicas can be
compared for consistency.
@@ -1733,6 +1732,7 @@ Internet-Draft WIMSE Execution Context February 2026
Nennemann Expires 28 August 2026 [Page 31]
Internet-Draft WIMSE Execution Context February 2026
@@ -2611,7 +2611,7 @@ Internet-Draft WIMSE Execution Context February 2026
"pol_decision": "approved",
"pol_enforcer": "spiffe://meddev.example/human/release-mgr-42",
"ext": {
"org.ietf.wimse.witnessed_by": [
"witnessed_by": [
"spiffe://meddev.example/audit/qa-observer-1"
]
}
@@ -2621,7 +2621,7 @@ Internet-Draft WIMSE Execution Context February 2026
implementation, implementation preceded testing, testing preceded
build, and a human release manager approved the final release. The
"ext" object in task 5 carries witness metadata via the
"org.ietf.wimse.witnessed_by" extension key.
"witnessed_by" extension key.

File diff suppressed because it is too large Load Diff