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

@@ -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)