From 102a120d6505acc280d45fe1f058b0d7a9fb3f80 Mon Sep 17 00:00:00 2001 From: Christian Nennemann Date: Tue, 24 Feb 2026 22:39:46 +0100 Subject: [PATCH] Merge tid into jti and make policy claims optional - Eliminate the "tid" claim; "jti" now serves as both token ID (for replay detection) and task ID (for DAG parent references in "par") - Make "pol" and "pol_decision" OPTIONAL (must be paired when present) - Regulated deployments SHOULD still include policy claims - Reduces required ECT-specific claims to just "exec_act" and "par" - Remove "tid" from IANA JWT Claims registration - Update all examples, pseudocode, and DAG validation rules Co-Authored-By: Claude Opus 4.6 --- ...-nennemann-wimse-execution-context-00.html | 209 ++- draft-nennemann-wimse-execution-context-00.md | 188 ++- ...t-nennemann-wimse-execution-context-00.txt | 546 +++---- ...t-nennemann-wimse-execution-context-00.xml | 1340 ++++++++--------- 4 files changed, 1072 insertions(+), 1211 deletions(-) diff --git a/draft-nennemann-wimse-execution-context-00.html b/draft-nennemann-wimse-execution-context-00.html index 8aee653..6ef1704 100644 --- a/draft-nennemann-wimse-execution-context-00.html +++ b/draft-nennemann-wimse-execution-context-00.html @@ -2180,11 +2180,15 @@ upon issuance.

jti:
-

REQUIRED. String. A unique identifier for the ECT in UUID -format [RFC9562]. Used for replay detection: receivers MUST -reject ECTs whose "jti" has already been seen within the -expiration window. The "jti" value MUST be unique across all -ECTs issued by the same agent.

+

REQUIRED. String. A globally unique identifier for both the +ECT and the task it records, in UUID format [RFC9562]. Since +each ECT represents exactly one task, "jti" serves as both the +token identifier (for replay detection) and the task identifier +(for DAG parent references in "par"). Receivers MUST reject +ECTs whose "jti" has already been seen within the expiration +window. When "wid" is present, uniqueness is scoped to the +workflow; when "wid" is absent, uniqueness MUST be enforced +globally across the ECT store.

@@ -2201,36 +2205,26 @@ ECTs issued by the same agent.¶<

OPTIONAL. String. A workflow identifier that groups related ECTs into a single workflow. When present, MUST be a UUID -[RFC9562]. When absent, the "tid" uniqueness requirement -applies globally across the entire ledger.

+[RFC9562].

-
tid:
+
exec_act:
-

REQUIRED. String. A globally unique task identifier in UUID -format [RFC9562]. Each task MUST have a unique "tid" value. -When "wid" is present, uniqueness is scoped to the workflow; -when "wid" is absent, uniqueness MUST be enforced globally -across the ledger.

-
-
-
exec_act:
-
-

REQUIRED. String. The action or task type identifier describing +

REQUIRED. String. The action or task type identifier describing what the agent performed (e.g., "process_payment", "validate_safety", "calculate_dosage"). Note: this claim is intentionally named "exec_act" rather than "act" to avoid collision with the "act" (Actor) claim registered by -[RFC8693].

+[RFC8693].

-
par:
-
-

REQUIRED. Array of strings. Parent task identifiers -representing DAG dependencies. Each element MUST be a valid -"tid" from a previously executed task. An empty array indicates +

par:
+
+

REQUIRED. Array of strings. Parent task identifiers +representing DAG dependencies. Each element MUST be the "jti" +value of a previously verified ECT. An empty array indicates a root task with no dependencies. A workflow MAY contain -multiple root tasks.

+multiple root tasks.

@@ -2245,17 +2239,18 @@ multiple root tasks.

pol:
-

REQUIRED. String. The identifier of the policy rule that was +

OPTIONAL. String. The identifier of the policy rule that was evaluated for this task (e.g., -"clinical_data_access_policy_v1").

+"clinical_data_access_policy_v1"). MUST be present when +"pol_decision" is present.

pol_decision:
-

REQUIRED. String. The result of the policy evaluation. MUST -be one of the values registered in the ECT Policy Decision -Values registry (Section 13.4). Initial values -are:

+

OPTIONAL. String. The result of the policy evaluation. When +present, MUST be one of the values registered in the ECT Policy +Decision Values registry (Section 13.4). MUST be +present when "pol" is present. Initial values are:

+

When "pol" and "pol_decision" are absent, the ECT records task +execution without a policy checkpoint. Regulated deployments +SHOULD include policy claims on all ECTs to maintain complete +audit trails.

pol_enforcer:
@@ -2463,10 +2463,9 @@ ECTs whose "ext" claim exceeds these limits. the following DAG validation steps:

  1. -

    Task ID Uniqueness: The "tid" claim MUST be unique within the +

    Task ID Uniqueness: The "jti" claim MUST be unique within the applicable scope (the workflow identified by "wid", or the -entire ECT store if "wid" is absent). If a task with the same -"tid" already exists, the ECT MUST be rejected.

    +entire ECT store if "wid" is absent). If an ECT with the same +"jti" already exists, the ECT MUST be rejected.

  2. Parent Existence: Every task identifier listed in the "par" @@ -2601,17 +2600,19 @@ ECT MUST be rejected.

  3. Acyclicity: Following the chain of parent references MUST NOT -lead back to the current task's "tid". If a cycle is detected, +lead back to the current ECT's "jti". If a cycle is detected, the ECT MUST be rejected.

  4. -

    Parent Policy Decision: If any parent task has a "pol_decision" -of "rejected" or "pending_human_review", the current task's -"exec_act" MUST indicate a compensation, rollback, remediation, -or human review action. Implementations MUST NOT accept an ECT -representing normal workflow continuation when a parent's -"pol_decision" is not "approved", unless the current ECT has -"compensation_required" set to true.

    +

    Parent Policy Decision: If any parent ECT contains a +"pol_decision" of "rejected" or "pending_human_review", the +current ECT's "exec_act" MUST indicate a compensation, +rollback, remediation, or human review action. +Implementations MUST NOT accept an ECT representing normal +workflow continuation when a parent's "pol_decision" is not +"approved", unless the current ECT has "compensation_required" +set to true. This rule only applies when the parent ECT +contains policy claims.

  5. Trust Domain Consistency: Parent tasks SHOULD belong to the @@ -2634,8 +2635,8 @@ relationship has been established. function validate_dag(ect, ect_store, clock_skew_tolerance): // ect_store: ledger or local cache of verified ECTs // Step 1: Uniqueness check - if ect_store.contains(ect.tid, ect.wid): - return error("Task ID already exists") + 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: @@ -2647,26 +2648,26 @@ function validate_dag(ect, ect_store, clock_skew_tolerance): // Step 3: Cycle detection (with traversal limit) visited = set() - result = has_cycle(ect.tid, ect.par, ect_store, 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_tid, parent_ids, ect_store, +function has_cycle(target_jti, parent_ids, ect_store, visited, max_depth): if visited.size() >= max_depth: return error("Maximum ancestor traversal limit exceeded") for parent_id in parent_ids: - if parent_id == target_tid: + if parent_id == target_jti: return true if parent_id in visited: continue visited.add(parent_id) parent = ect_store.get(parent_id) if parent is not null: - result = has_cycle(target_tid, parent.par, ect_store, + result = has_cycle(target_jti, parent.par, ect_store, visited, max_depth) if result is error or result is true: return result @@ -2757,12 +2758,13 @@ identity MUST appear in "aud".

  6. -

    Verify all required claims ("jti", "tid", "exec_act", "par", -"pol", "pol_decision") are present and well-formed.

    +

    Verify all required claims ("jti", "exec_act", "par") are +present and well-formed.

  7. -

    Verify "pol_decision" is one of "approved", "rejected", or -"pending_human_review".

    +

    If "pol" or "pol_decision" is present, verify that both are +present and that "pol_decision" is one of "approved", +"rejected", or "pending_human_review".

  8. Perform DAG validation per Section 6.

    @@ -2847,15 +2849,17 @@ function verify_ect(ect_jws, verifier_id, return reject("ECT issued in the future") // Verify required claims - for claim in ["jti", "tid", "exec_act", "par", - "pol", "pol_decision"]: + for claim in ["jti", "exec_act", "par"]: if claim not in payload: return reject("Missing required claim: " + claim) - // Validate pol_decision value - if payload.pol_decision not in - ["approved", "rejected", "pending_human_review"]: - return reject("Invalid pol_decision value") + // Validate policy claims (optional, but must be paired) + if "pol" in payload or "pol_decision" in payload: + if "pol" not in payload or "pol_decision" not in payload: + return reject("pol and pol_decision must both be present") + if payload.pol_decision not in + ["approved", "rejected", "pending_human_review"]: + return reject("Invalid pol_decision value") // Validate DAG (against ledger or inline parent ECTs) result = validate_dag(payload, ect_store, @@ -2921,7 +2925,7 @@ ECTs

  9. Global replay detection relies solely on "jti" caches at each -agent; there is no centralized "tid" uniqueness check

    +agent; there is no centralized "jti" uniqueness check

  10. The parent ECT chain grows with each hop, increasing HTTP @@ -3008,7 +3012,7 @@ entries via a monotonically increasing sequence number.

    Lookup by task ID: The ledger MUST support efficient retrieval -of ECT entries by "tid" value.

    +of ECT entries by "jti" value.

  11. Integrity verification: The ledger SHOULD provide a mechanism @@ -3032,7 +3036,7 @@ workflow agents to reduce the risk of collusion.

    Note: task identifiers in this section are abbreviated for -readability. In production, all "tid" values are required to be +readability. In production, all "jti" values are required to be UUIDs per Section 4.2.2.

    @@ -3088,27 +3092,27 @@ software used in medical devices.
     Agent A (Spec Reviewer):
    -  tid: task-001    par: []
    +  jti: task-001    par: []
       exec_act: review_requirements_spec
       pol: spec_review_policy_v2     pol_decision: approved
     
     Agent B (Code Generator):
    -  tid: task-002    par: [task-001]
    +  jti: task-002    par: [task-001]
       exec_act: implement_module
       pol: coding_standards_v3       pol_decision: approved
     
     Agent C (Test Agent):
    -  tid: task-003    par: [task-002]
    +  jti: task-003    par: [task-002]
       exec_act: execute_test_suite
       pol: test_coverage_policy_v1   pol_decision: approved
     
     Agent D (Build Agent):
    -  tid: task-004    par: [task-003]
    +  jti: task-004    par: [task-003]
       exec_act: build_release_artifact
       pol: build_validation_v2       pol_decision: approved
     
     Human Release Manager:
    -  tid: task-005    par: [task-004]
    +  jti: task-005    par: [task-004]
       exec_act: approve_release
       pol: release_approval_policy   pol_decision: approved
       pol_enforcer: spiffe://meddev.example/human/release-mgr-42
    @@ -3213,17 +3217,17 @@ execution.

     Agent A (Risk Assessment):
    -  tid: task-001    par: []
    +  jti: task-001    par: []
       exec_act: calculate_risk_exposure
       pol: risk_limits_policy_v2  pol_decision: approved
     
     Agent B (Compliance):
    -  tid: task-002    par: [task-001]
    +  jti: task-002    par: [task-001]
       exec_act: verify_compliance
       pol: compliance_check_v1    pol_decision: approved
     
     Agent C (Execution):
    -  tid: task-003    par: [task-002]
    +  jti: task-003    par: [task-002]
       exec_act: execute_trade
       pol: execution_policy_v3    pol_decision: approved
     
    @@ -3266,9 +3270,8 @@ a cryptographic link to the original task:<
     Agent A (Route Planning):
    -  tid: task-001    par: []
    +  jti: task-001    par: []
       exec_act: plan_route
       pol: route_policy_v1        pol_decision: approved
     
     Agent B (Customs):
    -  tid: task-002    par: [task-001]
    +  jti: task-002    par: [task-001]
       exec_act: validate_customs
       pol: customs_policy_v2      pol_decision: approved
     
     Agent C (Safety):
    -  tid: task-003    par: [task-001]
    +  jti: task-003    par: [task-001]
       exec_act: verify_cargo_safety
       pol: safety_policy_v1       pol_decision: approved
     
     Agent D (Payment):
    -  tid: task-004    par: [task-002, task-003]
    +  jti: task-004    par: [task-002, task-003]
       exec_act: authorize_payment
       pol: payment_policy_v3      pol_decision: approved
     
     System (Commitment):
    -  tid: task-005    par: [task-004]
    +  jti: task-005    par: [task-004]
       exec_act: commit_shipment
       pol: commitment_policy_v1   pol_decision: approved
     
    @@ -3422,7 +3425,7 @@ attestation ECT:

    specific equivalent).

  12. -

    MUST include the observed task's "tid" in the "par" array, +

    MUST include the observed task's "jti" in the "par" array, linking the attestation to the original task.

  13. @@ -3892,14 +3895,6 @@ the "JSON Web Token Claims" registry maintained by IANA:IETF Section 4.2.2 - - - - tid - Task Identifier - IETF - - Section 4.2.2 @@ -4438,8 +4433,8 @@ use cases are distinct.

    1. Create JWTs with all required claims ("iss", "aud", "iat", -"exp", "jti", "tid", "exec_act", "par", "pol", -"pol_decision").

      +"exp", "jti", "exec_act", "par") and policy claims ("pol", +"pol_decision") when policy evaluation was performed.

    2. Sign ECTs with the agent's private key using an algorithm @@ -4612,9 +4607,8 @@ Agent B:

      "aud": "spiffe://example.com/agent/validator", "iat": 1772064150, "exp": 1772064750, - "jti": "1a2b3c4d-e5f6-7890-abcd-ef0123456701", + "jti": "550e8400-e29b-41d4-a716-446655440001", "wid": "b1c2d3e4-f5a6-7890-bcde-f01234567890", - "tid": "550e8400-e29b-41d4-a716-446655440001", "exec_act": "fetch_patient_data", "par": [], "pol": "clinical_data_access_policy_v1", @@ -4636,9 +4630,8 @@ task, and creates its own ECT:= max_depth: return error("Maximum ancestor traversal limit exceeded") for parent_id in parent_ids: - if parent_id == target_tid: + if parent_id == target_jti: return true if parent_id in visited: continue visited.add(parent_id) parent = ect_store.get(parent_id) if parent is not null: - result = has_cycle(target_tid, parent.par, ect_store, + result = has_cycle(target_jti, parent.par, ect_store, visited, max_depth) if result is error or result is true: return result @@ -889,11 +892,12 @@ verification steps in order: (RECOMMENDED: no more than 30 seconds ahead of the verifier's current time, to account for clock skew). -12. Verify all required claims ("jti", "tid", "exec_act", "par", - "pol", "pol_decision") are present and well-formed. +12. Verify all required claims ("jti", "exec_act", "par") are + present and well-formed. -13. Verify "pol_decision" is one of "approved", "rejected", or - "pending_human_review". +13. If "pol" or "pol_decision" is present, verify that both are + present and that "pol_decision" is one of "approved", + "rejected", or "pending_human_review". 14. Perform DAG validation per {{dag-validation}}. @@ -969,15 +973,17 @@ function verify_ect(ect_jws, verifier_id, return reject("ECT issued in the future") // Verify required claims - for claim in ["jti", "tid", "exec_act", "par", - "pol", "pol_decision"]: + for claim in ["jti", "exec_act", "par"]: if claim not in payload: return reject("Missing required claim: " + claim) - // Validate pol_decision value - if payload.pol_decision not in - ["approved", "rejected", "pending_human_review"]: - return reject("Invalid pol_decision value") + // Validate policy claims (optional, but must be paired) + if "pol" in payload or "pol_decision" in payload: + if "pol" not in payload or "pol_decision" not in payload: + return reject("pol and pol_decision must both be present") + if payload.pol_decision not in + ["approved", "rejected", "pending_human_review"]: + return reject("Invalid pol_decision value") // Validate DAG (against ledger or inline parent ECTs) result = validate_dag(payload, ect_store, @@ -1023,7 +1029,7 @@ Limitations of point-to-point mode: - No persistent audit trail unless agents independently retain ECTs - Global replay detection relies solely on "jti" caches at each - agent; there is no centralized "tid" uniqueness check + agent; there is no centralized "jti" uniqueness check - The parent ECT chain grows with each hop, increasing HTTP header size - Post-hoc audit reconstruction requires collecting ECTs from @@ -1083,7 +1089,7 @@ An audit ledger implementation MUST provide: entries via a monotonically increasing sequence number. 3. Lookup by task ID: The ledger MUST support efficient retrieval - of ECT entries by "tid" value. + of ECT entries by "jti" value. 4. Integrity verification: The ledger SHOULD provide a mechanism to verify that no entries have been tampered with (e.g., @@ -1099,7 +1105,7 @@ Each ledger entry is a logical record containing: ~~~json { "ledger_sequence": 42, - "task_id": "550e8400-e29b-41d4-a716-446655440001", + "ect_jti": "550e8400-e29b-41d4-a716-446655440001", "agent_id": "spiffe://example.com/agent/clinical", "action": "recommend_treatment", "parents": [], @@ -1129,7 +1135,7 @@ include additional domain-specific requirements beyond the scope of this specification. Note: task identifiers in this section are abbreviated for -readability. In production, all "tid" values are required to be +readability. In production, all "jti" values are required to be UUIDs per {{exec-claims}}. ## Medical Device SDLC Workflow @@ -1143,27 +1149,27 @@ software used in medical devices. ~~~ Agent A (Spec Reviewer): - tid: task-001 par: [] + jti: task-001 par: [] exec_act: review_requirements_spec pol: spec_review_policy_v2 pol_decision: approved Agent B (Code Generator): - tid: task-002 par: [task-001] + jti: task-002 par: [task-001] exec_act: implement_module pol: coding_standards_v3 pol_decision: approved Agent C (Test Agent): - tid: task-003 par: [task-002] + jti: task-003 par: [task-002] exec_act: execute_test_suite pol: test_coverage_policy_v1 pol_decision: approved Agent D (Build Agent): - tid: task-004 par: [task-003] + jti: task-004 par: [task-003] exec_act: build_release_artifact pol: build_validation_v2 pol_decision: approved Human Release Manager: - tid: task-005 par: [task-004] + jti: task-005 par: [task-004] exec_act: approve_release pol: release_approval_policy pol_decision: approved pol_enforcer: spiffe://meddev.example/human/release-mgr-42 @@ -1231,17 +1237,17 @@ execution. ~~~ Agent A (Risk Assessment): - tid: task-001 par: [] + jti: task-001 par: [] exec_act: calculate_risk_exposure pol: risk_limits_policy_v2 pol_decision: approved Agent B (Compliance): - tid: task-002 par: [task-001] + jti: task-002 par: [task-001] exec_act: verify_compliance pol: compliance_check_v1 pol_decision: approved Agent C (Execution): - tid: task-003 par: [task-002] + jti: task-003 par: [task-002] exec_act: execute_trade pol: execution_policy_v3 pol_decision: approved ~~~ @@ -1268,9 +1274,8 @@ a cryptographic link to the original task: "aud": "spiffe://bank.example/system/ledger", "iat": 1772150550, "exp": 1772151150, - "jti": "e4f5a6b7-c8d9-0123-ef01-234567890abc", + "jti": "550e8400-e29b-41d4-a716-446655440099", "wid": "d3e4f5a6-b7c8-9012-def0-123456789012", - "tid": "550e8400-e29b-41d4-a716-446655440099", "exec_act": "initiate_trade_rollback", "par": ["550e8400-e29b-41d4-a716-446655440003"], "pol": "compensation_policy_v1", @@ -1294,27 +1299,27 @@ required checks were completed: ~~~ Agent A (Route Planning): - tid: task-001 par: [] + jti: task-001 par: [] exec_act: plan_route pol: route_policy_v1 pol_decision: approved Agent B (Customs): - tid: task-002 par: [task-001] + jti: task-002 par: [task-001] exec_act: validate_customs pol: customs_policy_v2 pol_decision: approved Agent C (Safety): - tid: task-003 par: [task-001] + jti: task-003 par: [task-001] exec_act: verify_cargo_safety pol: safety_policy_v1 pol_decision: approved Agent D (Payment): - tid: task-004 par: [task-002, task-003] + jti: task-004 par: [task-002, task-003] exec_act: authorize_payment pol: payment_policy_v3 pol_decision: approved System (Commitment): - tid: task-005 par: [task-004] + jti: task-005 par: [task-004] exec_act: commit_shipment pol: commitment_policy_v1 pol_decision: approved ~~~ @@ -1377,7 +1382,7 @@ attestation ECT: - MUST set "iss" to the witness's own workload identity. - MUST set "exec_act" to "witness_attestation" (or a domain- specific equivalent). -- MUST include the observed task's "tid" in the "par" array, +- MUST include the observed task's "jti" in the "par" array, linking the attestation to the original task. - MUST set "pol_decision" to "approved" to indicate the witness confirms the observation. @@ -1673,7 +1678,6 @@ the "JSON Web Token Claims" registry maintained by IANA: | Claim Name | Claim Description | Change Controller | Reference | |:---:|:---|:---:|:---:| | wid | Workflow Identifier | IETF | {{exec-claims}} | -| tid | Task Identifier | IETF | {{exec-claims}} | | exec_act | Action/Task Type | IETF | {{exec-claims}} | | par | Parent Task Identifiers | IETF | {{exec-claims}} | | pol | Policy Rule Identifier | IETF | {{policy-claims}} | @@ -1861,8 +1865,8 @@ use cases are distinct. A minimal conforming implementation needs to: 1. Create JWTs with all required claims ("iss", "aud", "iat", - "exp", "jti", "tid", "exec_act", "par", "pol", - "pol_decision"). + "exp", "jti", "exec_act", "par") and policy claims ("pol", + "pol_decision") when policy evaluation was performed. 2. Sign ECTs with the agent's private key using an algorithm matching the WIT (ES256 recommended). 3. Verify ECT signatures against WIT public keys. @@ -1950,9 +1954,8 @@ ECT Payload: "aud": "spiffe://example.com/agent/validator", "iat": 1772064150, "exp": 1772064750, - "jti": "1a2b3c4d-e5f6-7890-abcd-ef0123456701", + "jti": "550e8400-e29b-41d4-a716-446655440001", "wid": "b1c2d3e4-f5a6-7890-bcde-f01234567890", - "tid": "550e8400-e29b-41d4-a716-446655440001", "exec_act": "fetch_patient_data", "par": [], "pol": "clinical_data_access_policy_v1", @@ -1974,9 +1977,8 @@ task, and creates its own ECT: "aud": "spiffe://example.com/system/ledger", "iat": 1772064160, "exp": 1772064760, - "jti": "2b3c4d5e-f6a7-8901-bcde-f01234567802", + "jti": "550e8400-e29b-41d4-a716-446655440002", "wid": "b1c2d3e4-f5a6-7890-bcde-f01234567890", - "tid": "550e8400-e29b-41d4-a716-446655440002", "exec_act": "validate_safety", "par": ["550e8400-e29b-41d4-a716-446655440001"], "pol": "safety_validation_policy_v2", @@ -2010,9 +2012,8 @@ Task 1 (Spec Review Agent): "aud": "spiffe://meddev.example/agent/code-gen", "iat": 1772064150, "exp": 1772064750, - "jti": "3c4d5e6f-a7b8-9012-cdef-012345678903", + "jti": "a1b2c3d4-0001-0000-0000-000000000001", "wid": "c2d3e4f5-a6b7-8901-cdef-012345678901", - "tid": "a1b2c3d4-0001-0000-0000-000000000001", "exec_act": "review_requirements_spec", "par": [], "pol": "spec_review_policy_v2", @@ -2033,9 +2034,8 @@ Task 2 (Code Generation Agent): "aud": "spiffe://meddev.example/agent/test-runner", "iat": 1772064200, "exp": 1772064800, - "jti": "4d5e6f7a-b8c9-0123-def0-123456789004", + "jti": "a1b2c3d4-0001-0000-0000-000000000002", "wid": "c2d3e4f5-a6b7-8901-cdef-012345678901", - "tid": "a1b2c3d4-0001-0000-0000-000000000002", "exec_act": "implement_module", "par": ["a1b2c3d4-0001-0000-0000-000000000001"], "pol": "coding_standards_v3", @@ -2054,9 +2054,8 @@ Task 3 (Autonomous Test Agent): "aud": "spiffe://meddev.example/agent/build", "iat": 1772064260, "exp": 1772064860, - "jti": "5e6f7a8b-c9d0-1234-ef01-234567890005", + "jti": "a1b2c3d4-0001-0000-0000-000000000003", "wid": "c2d3e4f5-a6b7-8901-cdef-012345678901", - "tid": "a1b2c3d4-0001-0000-0000-000000000003", "exec_act": "execute_test_suite", "par": ["a1b2c3d4-0001-0000-0000-000000000002"], "pol": "test_coverage_policy_v1", @@ -2075,9 +2074,8 @@ Task 4 (Build Agent): "aud": "spiffe://meddev.example/human/release-mgr-42", "iat": 1772064310, "exp": 1772064910, - "jti": "6f7a8b9c-d0e1-2345-f012-345678900006", + "jti": "a1b2c3d4-0001-0000-0000-000000000004", "wid": "c2d3e4f5-a6b7-8901-cdef-012345678901", - "tid": "a1b2c3d4-0001-0000-0000-000000000004", "exec_act": "build_release_artifact", "par": ["a1b2c3d4-0001-0000-0000-000000000003"], "pol": "build_validation_v2", @@ -2096,9 +2094,8 @@ Task 5 (Human Release Manager Approval): "aud": "spiffe://meddev.example/system/ledger", "iat": 1772064510, "exp": 1772065110, - "jti": "7a8b9c0d-e1f2-3456-0123-456789000007", + "jti": "a1b2c3d4-0001-0000-0000-000000000005", "wid": "c2d3e4f5-a6b7-8901-cdef-012345678901", - "tid": "a1b2c3d4-0001-0000-0000-000000000005", "exec_act": "approve_release", "par": ["a1b2c3d4-0001-0000-0000-000000000004"], "pol": "release_approval_policy", @@ -2165,9 +2162,8 @@ Task 004 ECT payload: "aud": "spiffe://bank.example/system/ledger", "iat": 1772064250, "exp": 1772064850, - "jti": "8b9c0d1e-f2a3-4567-1234-567890000008", + "jti": "f1e2d3c4-0004-0000-0000-000000000004", "wid": "d3e4f5a6-b7c8-9012-def0-123456789012", - "tid": "f1e2d3c4-0004-0000-0000-000000000004", "exec_act": "execute_trade", "par": [ "f1e2d3c4-0002-0000-0000-000000000002", diff --git a/draft-nennemann-wimse-execution-context-00.txt b/draft-nennemann-wimse-execution-context-00.txt index 4992725..261d32c 100644 --- a/draft-nennemann-wimse-execution-context-00.txt +++ b/draft-nennemann-wimse-execution-context-00.txt @@ -149,7 +149,7 @@ Internet-Draft WIMSE Execution Context February 2026 13.2. HTTP Header Field Registration . . . . . . . . . . . . . 36 13.3. JWT Claims Registration . . . . . . . . . . . . . . . . 37 13.4. ECT Policy Decision Values Registry . . . . . . . . . . 38 - 13.5. ECT Regulated Domain Values Registry . . . . . . . . . . 39 + 13.5. ECT Regulated Domain Values Registry . . . . . . . . . . 38 14. References . . . . . . . . . . . . . . . . . . . . . . . . . 39 14.1. Normative References . . . . . . . . . . . . . . . . . . 39 14.2. Informative References . . . . . . . . . . . . . . . . . 40 @@ -157,11 +157,11 @@ Internet-Draft WIMSE Execution Context February 2026 WIMSE Workload Identity . . . . . . . . . . . . . . . . . . . . 42 OAuth 2.0 Token Exchange and the "act" Claim . . . . . . . . . 42 Transaction Tokens . . . . . . . . . . . . . . . . . . . . . . 43 - Distributed Tracing (OpenTelemetry) . . . . . . . . . . . . . . 44 + Distributed Tracing (OpenTelemetry) . . . . . . . . . . . . . . 43 Blockchain and Distributed Ledgers . . . . . . . . . . . . . . 44 SCITT (Supply Chain Integrity, Transparency, and Trust) . . . . 44 - W3C Verifiable Credentials . . . . . . . . . . . . . . . . . . 45 - Implementation Guidance . . . . . . . . . . . . . . . . . . . . . 45 + W3C Verifiable Credentials . . . . . . . . . . . . . . . . . . 44 + Implementation Guidance . . . . . . . . . . . . . . . . . . . . . 44 @@ -170,17 +170,17 @@ Nennemann Expires 28 August 2026 [Page 3] Internet-Draft WIMSE Execution Context February 2026 - Minimal Implementation . . . . . . . . . . . . . . . . . . . . 45 + Minimal Implementation . . . . . . . . . . . . . . . . . . . . 44 Storage Recommendations . . . . . . . . . . . . . . . . . . . . 45 Performance Considerations . . . . . . . . . . . . . . . . . . 45 - Interoperability . . . . . . . . . . . . . . . . . . . . . . . 46 + Interoperability . . . . . . . . . . . . . . . . . . . . . . . 45 Regulatory Compliance Mapping . . . . . . . . . . . . . . . . . . 46 - Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47 - Example 1: Simple Two-Agent Workflow . . . . . . . . . . . . . 47 - Example 2: Medical Device SDLC with Release Approval . . . . . 49 - Example 3: Parallel Execution with Join . . . . . . . . . . . . 52 - Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . . . 52 - Author's Address . . . . . . . . . . . . . . . . . . . . . . . . 53 + Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46 + Example 1: Simple Two-Agent Workflow . . . . . . . . . . . . . 46 + Example 2: Medical Device SDLC with Release Approval . . . . . 48 + Example 3: Parallel Execution with Join . . . . . . . . . . . . 50 + Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . . . 51 + Author's Address . . . . . . . . . . . . . . . . . . . . . . . . 51 1. Introduction @@ -589,11 +589,15 @@ Internet-Draft WIMSE Execution Context February 2026 ECTs record completed actions and are valid immediately upon issuance. - jti: REQUIRED. String. A unique identifier for the ECT in UUID - format [RFC9562]. Used for replay detection: receivers MUST - reject ECTs whose "jti" has already been seen within the - expiration window. The "jti" value MUST be unique across all ECTs - issued by the same agent. + jti: REQUIRED. String. A globally unique identifier for both the + ECT and the task it records, in UUID format [RFC9562]. Since each + ECT represents exactly one task, "jti" serves as both the token + identifier (for replay detection) and the task identifier (for DAG + parent references in "par"). Receivers MUST reject ECTs whose + "jti" has already been seen within the expiration window. When + "wid" is present, uniqueness is scoped to the workflow; when "wid" + is absent, uniqueness MUST be enforced globally across the ECT + store. 4.2.2. Execution Context @@ -601,18 +605,14 @@ Internet-Draft WIMSE Execution Context February 2026 wid: OPTIONAL. String. A workflow identifier that groups related ECTs into a single workflow. When present, MUST be a UUID - [RFC9562]. When absent, the "tid" uniqueness requirement applies - globally across the entire ledger. - - tid: REQUIRED. String. A globally unique task identifier in UUID - format [RFC9562]. Each task MUST have a unique "tid" value. When - "wid" is present, uniqueness is scoped to the workflow; when "wid" - is absent, uniqueness MUST be enforced globally across the ledger. + [RFC9562]. exec_act: REQUIRED. String. The action or task type identifier + + Nennemann Expires 28 August 2026 [Page 11] Internet-Draft WIMSE Execution Context February 2026 @@ -624,33 +624,34 @@ Internet-Draft WIMSE Execution Context February 2026 collision with the "act" (Actor) claim registered by [RFC8693]. par: REQUIRED. Array of strings. Parent task identifiers - representing DAG dependencies. Each element MUST be a valid "tid" - from a previously executed task. An empty array indicates a root - task with no dependencies. A workflow MAY contain multiple root - tasks. + representing DAG dependencies. Each element MUST be the "jti" + value of a previously verified ECT. An empty array indicates a + root task with no dependencies. A workflow MAY contain multiple + root tasks. 4.2.3. Policy Evaluation The following claims record policy evaluation outcomes: - pol: REQUIRED. String. The identifier of the policy rule that was + pol: OPTIONAL. String. The identifier of the policy rule that was evaluated for this task (e.g., "clinical_data_access_policy_v1"). + MUST be present when "pol_decision" is present. - pol_decision: REQUIRED. String. The result of the policy - evaluation. MUST be one of the values registered in the ECT - Policy Decision Values registry (Section 13.4). Initial values - are: + pol_decision: OPTIONAL. String. The result of the policy + evaluation. When present, MUST be one of the values registered in + the ECT Policy Decision Values registry (Section 13.4). MUST be + present when "pol" is present. Initial values are: * "approved": The policy evaluation succeeded and the task was authorized to proceed. * "rejected": The policy evaluation failed. A "rejected" ECT - MUST still be appended to the audit ledger for accountability. - An ECT with "pol_decision" of "rejected" MAY appear as a parent - in the "par" array of a subsequent ECT, but only for - compensation, rollback, or remediation tasks. Agents MUST NOT - proceed with normal workflow execution based on a parent ECT - whose "pol_decision" is "rejected". + MUST still be recorded for accountability. An ECT with + "pol_decision" of "rejected" MAY appear as a parent in the + "par" array of a subsequent ECT, but only for compensation, + rollback, or remediation tasks. Agents MUST NOT proceed with + normal workflow execution based on a parent ECT whose + "pol_decision" is "rejected". * "pending_human_review": The policy evaluation requires human judgment before proceeding. Agents MUST NOT proceed with @@ -658,13 +659,12 @@ Internet-Draft WIMSE Execution Context February 2026 records an "approved" decision referencing this task as a parent. - pol_enforcer: OPTIONAL. StringOrURI. The identity of the entity - (system or person) that evaluated the policy decision. When - present, SHOULD use SPIFFE ID format. + When "pol" and "pol_decision" are absent, the ECT records task + execution without a policy checkpoint. Regulated deployments + SHOULD include policy claims on all ECTs to maintain complete + audit trails. - pol_timestamp: OPTIONAL. NumericDate. The time at which the policy - decision was made. When present, MUST be equal to or earlier than - the "iat" claim. + pol_enforcer: OPTIONAL. StringOrURI. The identity of the entity @@ -674,6 +674,13 @@ Nennemann Expires 28 August 2026 [Page 12] Internet-Draft WIMSE Execution Context February 2026 + (system or person) that evaluated the policy decision. When + present, SHOULD use SPIFFE ID format. + + pol_timestamp: OPTIONAL. NumericDate. The time at which the policy + decision was made. When present, MUST be equal to or earlier than + the "iat" claim. + This specification intentionally defines only the recording of policy evaluation outcomes. The mechanisms by which policies are defined, distributed to agents, and evaluated are out of scope. The "pol" @@ -715,13 +722,6 @@ Internet-Draft WIMSE Execution Context February 2026 exec_time_ms: OPTIONAL. Integer. The execution duration of the task in milliseconds. MUST be a non-negative integer. - regulated_domain: OPTIONAL. String. The regulatory domain - applicable to this task. Values MUST be registered in the ECT - Regulated Domain Values registry (Section 13.5). - - model_version: OPTIONAL. String. The version identifier of the AI - or ML model used to perform the task, if applicable. - @@ -730,6 +730,13 @@ Nennemann Expires 28 August 2026 [Page 13] Internet-Draft WIMSE Execution Context February 2026 + regulated_domain: OPTIONAL. String. The regulatory domain + applicable to this task. Values MUST be registered in the ECT + Regulated Domain Values registry (Section 13.5). + + model_version: OPTIONAL. String. The version identifier of the AI + or ML model used to perform the task, if applicable. + witnessed_by: OPTIONAL. Array of StringOrURI. Identifiers of third-party entities that the issuing agent claims observed or attested to the execution of this task. When present, each @@ -771,13 +778,6 @@ Internet-Draft WIMSE Execution Context February 2026 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. - - @@ -786,6 +786,12 @@ Nennemann Expires 28 August 2026 [Page 14] Internet-Draft WIMSE Execution Context February 2026 + 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. + 4.3. Complete ECT Example The following is a complete ECT payload example: @@ -796,10 +802,9 @@ Internet-Draft WIMSE Execution Context February 2026 "aud": "spiffe://example.com/agent/safety", "iat": 1772064150, "exp": 1772064750, - "jti": "7f3a8b2c-d1e4-4f56-9a0b-c3d4e5f6a7b8", + "jti": "550e8400-e29b-41d4-a716-446655440001", "wid": "a0b1c2d3-e4f5-6789-abcd-ef0123456789", - "tid": "550e8400-e29b-41d4-a716-446655440001", "exec_act": "recommend_treatment", "par": [], @@ -829,11 +834,6 @@ Internet-Draft WIMSE Execution Context February 2026 This specification defines the Execution-Context HTTP header field [RFC9110] for transporting ECTs between agents. - The header field value is the ECT in JWS Compact Serialization format - [RFC7515]. The value consists of three Base64url-encoded parts - separated by period (".") characters. - - @@ -842,6 +842,10 @@ Nennemann Expires 28 August 2026 [Page 15] Internet-Draft WIMSE Execution Context February 2026 + The header field value is the ECT in JWS Compact Serialization format + [RFC7515]. The value consists of three Base64url-encoded parts + separated by period (".") characters. + An agent sending a request to another agent includes the Execution- Context header alongside the WIMSE Workload-Identity and Workload- Proof-Token headers: @@ -889,18 +893,14 @@ Internet-Draft WIMSE Execution Context February 2026 - - - - Nennemann Expires 28 August 2026 [Page 16] Internet-Draft WIMSE Execution Context February 2026 - 1. Task ID Uniqueness: The "tid" claim MUST be unique within the + 1. Task ID Uniqueness: The "jti" claim MUST be unique within the applicable scope (the workflow identified by "wid", or the entire - ECT store if "wid" is absent). If a task with the same "tid" + ECT store if "wid" is absent). If an ECT with the same "jti" already exists, the ECT MUST be rejected. 2. Parent Existence: Every task identifier listed in the "par" array @@ -921,16 +921,17 @@ Internet-Draft WIMSE Execution Context February 2026 MUST be rejected. 4. Acyclicity: Following the chain of parent references MUST NOT - lead back to the current task's "tid". If a cycle is detected, + lead back to the current ECT's "jti". If a cycle is detected, the ECT MUST be rejected. - 5. Parent Policy Decision: If any parent task has a "pol_decision" - of "rejected" or "pending_human_review", the current task's - "exec_act" MUST indicate a compensation, rollback, remediation, - or human review action. Implementations MUST NOT accept an ECT - representing normal workflow continuation when a parent's - "pol_decision" is not "approved", unless the current ECT has - "compensation_required" set to true. + 5. Parent Policy Decision: If any parent ECT contains a + "pol_decision" of "rejected" or "pending_human_review", the + current ECT's "exec_act" MUST indicate a compensation, rollback, + remediation, or human review action. Implementations MUST NOT + accept an ECT representing normal workflow continuation when a + parent's "pol_decision" is not "approved", unless the current ECT + has "compensation_required" set to true. This rule only applies + when the parent ECT contains policy claims. 6. Trust Domain Consistency: Parent tasks SHOULD belong to the same trust domain or to a trust domain with which a federation @@ -948,7 +949,6 @@ Internet-Draft WIMSE Execution Context February 2026 - Nennemann Expires 28 August 2026 [Page 17] Internet-Draft WIMSE Execution Context February 2026 @@ -957,8 +957,8 @@ Internet-Draft WIMSE Execution Context February 2026 function validate_dag(ect, ect_store, clock_skew_tolerance): // ect_store: ledger or local cache of verified ECTs // Step 1: Uniqueness check - if ect_store.contains(ect.tid, ect.wid): - return error("Task ID already exists") + 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: @@ -970,26 +970,26 @@ Internet-Draft WIMSE Execution Context February 2026 // Step 3: Cycle detection (with traversal limit) visited = set() - result = has_cycle(ect.tid, ect.par, ect_store, 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_tid, parent_ids, ect_store, + function has_cycle(target_jti, parent_ids, ect_store, visited, max_depth): if visited.size() >= max_depth: return error("Maximum ancestor traversal limit exceeded") for parent_id in parent_ids: - if parent_id == target_tid: + if parent_id == target_jti: return true if parent_id in visited: continue visited.add(parent_id) parent = ect_store.get(parent_id) if parent is not null: - result = has_cycle(target_tid, parent.par, ect_store, + result = has_cycle(target_jti, parent.par, ect_store, visited, max_depth) if result is error or result is true: return result @@ -1072,11 +1072,12 @@ Internet-Draft WIMSE Execution Context February 2026 no more than 30 seconds ahead of the verifier's current time, to account for clock skew). - 12. Verify all required claims ("jti", "tid", "exec_act", "par", - "pol", "pol_decision") are present and well-formed. + 12. Verify all required claims ("jti", "exec_act", "par") are + present and well-formed. - 13. Verify "pol_decision" is one of "approved", "rejected", or - "pending_human_review". + 13. If "pol" or "pol_decision" is present, verify that both are + present and that "pol_decision" is one of "approved", + "rejected", or "pending_human_review". 14. Perform DAG validation per Section 6. @@ -1113,7 +1114,6 @@ Internet-Draft WIMSE Execution Context February 2026 return reject("Prohibited algorithm") // Look up public key - public_key = trust_domain_keys.get(header.kid) @@ -1122,6 +1122,7 @@ Nennemann Expires 28 August 2026 [Page 20] Internet-Draft WIMSE Execution Context February 2026 + public_key = trust_domain_keys.get(header.kid) if public_key is null: return reject("Unknown key identifier") @@ -1158,18 +1159,17 @@ Internet-Draft WIMSE Execution Context February 2026 return reject("ECT issued in the future") // Verify required claims - for claim in ["jti", "tid", "exec_act", "par", - "pol", "pol_decision"]: + for claim in ["jti", "exec_act", "par"]: if claim not in payload: return reject("Missing required claim: " + claim) - // Validate pol_decision value - if payload.pol_decision not in - ["approved", "rejected", "pending_human_review"]: - return reject("Invalid pol_decision value") - - // Validate DAG (against ledger or inline parent ECTs) - result = validate_dag(payload, ect_store, + // Validate policy claims (optional, but must be paired) + if "pol" in payload or "pol_decision" in payload: + if "pol" not in payload or "pol_decision" not in payload: + return reject("pol and pol_decision must both be present") + if payload.pol_decision not in + ["approved", "rejected", "pending_human_review"]: + return reject("Invalid pol_decision value") @@ -1178,6 +1178,8 @@ Nennemann Expires 28 August 2026 [Page 21] Internet-Draft WIMSE Execution Context February 2026 + // Validate DAG (against ledger or inline parent ECTs) + result = validate_dag(payload, ect_store, clock_skew_tolerance) if result is error: return reject("DAG validation failed") @@ -1221,10 +1223,8 @@ Internet-Draft WIMSE Execution Context February 2026 * No persistent audit trail unless agents independently retain ECTs * Global replay detection relies solely on "jti" caches at each - agent; there is no centralized "tid" uniqueness check + agent; there is no centralized "jti" uniqueness check - * The parent ECT chain grows with each hop, increasing HTTP header - size @@ -1234,6 +1234,9 @@ Nennemann Expires 28 August 2026 [Page 22] Internet-Draft WIMSE Execution Context February 2026 + * The parent ECT chain grows with each hop, increasing HTTP header + size + * Post-hoc audit reconstruction requires collecting ECTs from multiple agents @@ -1282,9 +1285,6 @@ Internet-Draft WIMSE Execution Context February 2026 - - - Nennemann Expires 28 August 2026 [Page 23] Internet-Draft WIMSE Execution Context February 2026 @@ -1301,7 +1301,7 @@ Internet-Draft WIMSE Execution Context February 2026 entries via a monotonically increasing sequence number. 3. Lookup by task ID: The ledger MUST support efficient retrieval of - ECT entries by "tid" value. + ECT entries by "jti" value. 4. Integrity verification: The ledger SHOULD provide a mechanism to verify that no entries have been tampered with (e.g., hash chains @@ -1316,7 +1316,7 @@ Internet-Draft WIMSE Execution Context February 2026 { "ledger_sequence": 42, - "task_id": "550e8400-e29b-41d4-a716-446655440001", + "ect_jti": "550e8400-e29b-41d4-a716-446655440001", "agent_id": "spiffe://example.com/agent/clinical", "action": "recommend_treatment", "parents": [], @@ -1355,7 +1355,7 @@ Internet-Draft WIMSE Execution Context February 2026 this specification. Note: task identifiers in this section are abbreviated for - readability. In production, all "tid" values are required to be + readability. In production, all "jti" values are required to be UUIDs per Section 4.2.2. 10.1. Medical Device SDLC Workflow @@ -1367,27 +1367,27 @@ Internet-Draft WIMSE Execution Context February 2026 complete development process for software used in medical devices. Agent A (Spec Reviewer): - tid: task-001 par: [] + jti: task-001 par: [] exec_act: review_requirements_spec pol: spec_review_policy_v2 pol_decision: approved Agent B (Code Generator): - tid: task-002 par: [task-001] + jti: task-002 par: [task-001] exec_act: implement_module pol: coding_standards_v3 pol_decision: approved Agent C (Test Agent): - tid: task-003 par: [task-002] + jti: task-003 par: [task-002] exec_act: execute_test_suite pol: test_coverage_policy_v1 pol_decision: approved Agent D (Build Agent): - tid: task-004 par: [task-003] + jti: task-004 par: [task-003] exec_act: build_release_artifact pol: build_validation_v2 pol_decision: approved Human Release Manager: - tid: task-005 par: [task-004] + jti: task-005 par: [task-004] exec_act: approve_release pol: release_approval_policy pol_decision: approved pol_enforcer: spiffe://meddev.example/human/release-mgr-42 @@ -1474,17 +1474,17 @@ Internet-Draft WIMSE Execution Context February 2026 records that compliance checks were evaluated before trade execution. Agent A (Risk Assessment): - tid: task-001 par: [] + jti: task-001 par: [] exec_act: calculate_risk_exposure pol: risk_limits_policy_v2 pol_decision: approved Agent B (Compliance): - tid: task-002 par: [task-001] + jti: task-002 par: [task-001] exec_act: verify_compliance pol: compliance_check_v1 pol_decision: approved Agent C (Execution): - tid: task-003 par: [task-002] + jti: task-003 par: [task-002] exec_act: execute_trade pol: execution_policy_v3 pol_decision: approved @@ -1520,9 +1520,8 @@ Internet-Draft WIMSE Execution Context February 2026 "aud": "spiffe://bank.example/system/ledger", "iat": 1772150550, "exp": 1772151150, - "jti": "e4f5a6b7-c8d9-0123-ef01-234567890abc", + "jti": "550e8400-e29b-41d4-a716-446655440099", "wid": "d3e4f5a6-b7c8-9012-def0-123456789012", - "tid": "550e8400-e29b-41d4-a716-446655440099", "exec_act": "initiate_trade_rollback", "par": ["550e8400-e29b-41d4-a716-446655440003"], "pol": "compensation_policy_v1", @@ -1563,6 +1562,7 @@ Internet-Draft WIMSE Execution Context February 2026 + Nennemann Expires 28 August 2026 [Page 28] @@ -1571,27 +1571,27 @@ Internet-Draft WIMSE Execution Context February 2026 Agent A (Route Planning): - tid: task-001 par: [] + jti: task-001 par: [] exec_act: plan_route pol: route_policy_v1 pol_decision: approved Agent B (Customs): - tid: task-002 par: [task-001] + jti: task-002 par: [task-001] exec_act: validate_customs pol: customs_policy_v2 pol_decision: approved Agent C (Safety): - tid: task-003 par: [task-001] + jti: task-003 par: [task-001] exec_act: verify_cargo_safety pol: safety_policy_v1 pol_decision: approved Agent D (Payment): - tid: task-004 par: [task-002, task-003] + jti: task-004 par: [task-002, task-003] exec_act: authorize_payment pol: payment_policy_v3 pol_decision: approved System (Commitment): - tid: task-005 par: [task-004] + jti: task-005 par: [task-004] exec_act: commit_shipment pol: commitment_policy_v1 pol_decision: approved @@ -1668,7 +1668,7 @@ Internet-Draft WIMSE Execution Context February 2026 * MUST set "exec_act" to "witness_attestation" (or a domain- specific equivalent). - * MUST include the observed task's "tid" in the "par" array, linking + * MUST include the observed task's "jti" in the "par" array, linking the attestation to the original task. * MUST set "pol_decision" to "approved" to indicate the witness @@ -2030,9 +2030,6 @@ Internet-Draft WIMSE Execution Context February 2026 | wid | Workflow | IETF | Section | | | Identifier | | 4.2.2 | +-----------------------+-----------------+------------+-----------+ - | tid | Task Identifier | IETF | Section | - | | | | 4.2.2 | - +-----------------------+-----------------+------------+-----------+ | exec_act | Action/Task | IETF | Section | | | Type | | 4.2.2 | +-----------------------+-----------------+------------+-----------+ @@ -2066,6 +2063,9 @@ Internet-Draft WIMSE Execution Context February 2026 | witnessed_by | Witness | IETF | Section | | | Identities | | 4.2.5 | +-----------------------+-----------------+------------+-----------+ + | regulated_domain | Regulatory | IETF | Section | + | | Domain | | 4.2.5 | + +-----------------------+-----------------+------------+-----------+ @@ -2074,9 +2074,6 @@ Nennemann Expires 28 August 2026 [Page 37] Internet-Draft WIMSE Execution Context February 2026 - | regulated_domain | Regulatory | IETF | Section | - | | Domain | | 4.2.5 | - +-----------------------+-----------------+------------+-----------+ | model_version | AI/ML Model | IETF | Section | | | Version | | 4.2.5 | +-----------------------+-----------------+------------+-----------+ @@ -2119,8 +2116,11 @@ Internet-Draft WIMSE Execution Context February 2026 Table 2: ECT Policy Decision Values +13.5. ECT Regulated Domain Values Registry - + This document establishes the "ECT Regulated Domain Values" registry + under the "JSON Web Token (JWT)" group. Registration policy is + Specification Required per [RFC8126]. @@ -2130,12 +2130,6 @@ Nennemann Expires 28 August 2026 [Page 38] Internet-Draft WIMSE Execution Context February 2026 -13.5. ECT Regulated Domain Values Registry - - This document establishes the "ECT Regulated Domain Values" registry - under the "JSON Web Token (JWT)" group. Registration policy is - Specification Required per [RFC8126]. - The initial contents of the registry are: +==========+====================+===================+===========+ @@ -2178,6 +2172,12 @@ Internet-Draft WIMSE Execution Context February 2026 DOI 10.17487/RFC2119, March 1997, . + [RFC7515] Jones, M., Bradley, J., and N. Sakimura, "JSON Web + Signature (JWS)", RFC 7515, DOI 10.17487/RFC7515, May + 2015, . + + + @@ -2186,10 +2186,6 @@ Nennemann Expires 28 August 2026 [Page 39] Internet-Draft WIMSE Execution Context February 2026 - [RFC7515] Jones, M., Bradley, J., and N. Sakimura, "JSON Web - Signature (JWS)", RFC 7515, DOI 10.17487/RFC7515, May - 2015, . - [RFC7517] Jones, M., "JSON Web Key (JWK)", RFC 7517, DOI 10.17487/RFC7517, May 2015, . @@ -2234,6 +2230,10 @@ Internet-Draft WIMSE Execution Context February 2026 intelligence (Artificial Intelligence Act)", 13 June 2024, . + [EU-MDR] European Parliament and Council of the European Union, + "Regulation (EU) 2017/745 on medical devices (MDR)", 5 + April 2017, . + @@ -2242,10 +2242,6 @@ Nennemann Expires 28 August 2026 [Page 40] Internet-Draft WIMSE Execution Context February 2026 - [EU-MDR] European Parliament and Council of the European Union, - "Regulation (EU) 2017/745 on medical devices (MDR)", 5 - April 2017, . - [FDA-21CFR11] U.S. Food and Drug Administration, "Title 21, Code of Federal Regulations, Part 11: Electronic Records; @@ -2287,6 +2283,10 @@ Internet-Draft WIMSE Execution Context February 2026 II)", 15 May 2014, . + [OPENTELEMETRY] + Cloud Native Computing Foundation, "OpenTelemetry + Specification", + . @@ -2298,11 +2298,6 @@ Nennemann Expires 28 August 2026 [Page 41] Internet-Draft WIMSE Execution Context February 2026 - [OPENTELEMETRY] - Cloud Native Computing Foundation, "OpenTelemetry - Specification", - . - [RFC3552] Rescorla, E. and B. Korver, "Guidelines for Writing RFC Text on Security Considerations", BCP 72, RFC 3552, DOI 10.17487/RFC3552, July 2003, @@ -2346,6 +2341,11 @@ OAuth 2.0 Token Exchange and the "act" Claim branching (fan-out) or convergence (fan-in) and therefore cannot form a DAG. + ECTs intentionally use the distinct claim name "exec_act" for the + action/task type to avoid collision with the "act" claim. The two + concepts are orthogonal: "act" records "who authorized whom," ECTs + record "what was done, in what order, with what policy outcomes." + @@ -2354,11 +2354,6 @@ Nennemann Expires 28 August 2026 [Page 42] Internet-Draft WIMSE Execution Context February 2026 - ECTs intentionally use the distinct claim name "exec_act" for the - action/task type to avoid collision with the "act" claim. The two - concepts are orthogonal: "act" records "who authorized whom," ECTs - record "what was done, in what order, with what policy outcomes." - Transaction Tokens OAuth Transaction Tokens [I-D.ietf-oauth-transaction-tokens] @@ -2396,20 +2391,6 @@ Transaction Tokens WPT to a co-present Txn-Token; a similar binding mechanism for ECTs is a potential future extension. - - - - - - - - - -Nennemann Expires 28 August 2026 [Page 43] - -Internet-Draft WIMSE Execution Context February 2026 - - Distributed Tracing (OpenTelemetry) OpenTelemetry [OPENTELEMETRY] and similar distributed tracing systems @@ -2421,6 +2402,14 @@ Distributed Tracing (OpenTelemetry) OpenTelemetry data is typically controlled by the platform operator and can be modified or deleted without detection. ECTs and distributed traces are complementary: traces provide observability + + + +Nennemann Expires 28 August 2026 [Page 43] + +Internet-Draft WIMSE Execution Context February 2026 + + while ECTs provide signed execution records. ECTs may reference OpenTelemetry trace identifiers in the "ext" claim for correlation. @@ -2453,19 +2442,6 @@ SCITT (Supply Chain Integrity, Transparency, and Trust) Transparency Service identifiers or Receipt references for tighter integration. - - - - - - - - -Nennemann Expires 28 August 2026 [Page 44] - -Internet-Draft WIMSE Execution Context February 2026 - - W3C Verifiable Credentials W3C Verifiable Credentials represent claims about subjects (e.g., @@ -2480,8 +2456,19 @@ Minimal Implementation A minimal conforming implementation needs to: + + + + + +Nennemann Expires 28 August 2026 [Page 44] + +Internet-Draft WIMSE Execution Context February 2026 + + 1. Create JWTs with all required claims ("iss", "aud", "iat", "exp", - "jti", "tid", "exec_act", "par", "pol", "pol_decision"). + "jti", "exec_act", "par") and policy claims ("pol", + "pol_decision") when policy evaluation was performed. 2. Sign ECTs with the agent's private key using an algorithm matching the WIT (ES256 recommended). @@ -2515,13 +2502,6 @@ Performance Considerations * DAG validation: O(V) where V is the number of reachable ancestor nodes (typically small for shallow workflows). - - -Nennemann Expires 28 August 2026 [Page 45] - -Internet-Draft WIMSE Execution Context February 2026 - - * JSON serialization: sub-millisecond per ECT. * Total per-request overhead: approximately 5-10ms, acceptable for @@ -2535,6 +2515,13 @@ Interoperability expected to be tested against multiple JWT libraries to ensure interoperability. + + +Nennemann Expires 28 August 2026 [Page 45] + +Internet-Draft WIMSE Execution Context February 2026 + + Regulatory Compliance Mapping The following table summarizes how ECTs can contribute to compliance @@ -2542,42 +2529,6 @@ Regulatory Compliance Mapping block; achieving compliance requires additional organizational measures beyond this specification. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Nennemann Expires 28 August 2026 [Page 46] - -Internet-Draft WIMSE Execution Context February 2026 - - +============+========================+==========================+ | Regulation | Requirement | ECT Contribution | +============+========================+==========================+ @@ -2618,6 +2569,15 @@ Example 1: Simple Two-Agent Workflow ECT JOSE Header: + + + + +Nennemann Expires 28 August 2026 [Page 46] + +Internet-Draft WIMSE Execution Context February 2026 + + { "alg": "ES256", "typ": "wimse-exec+jwt", @@ -2626,23 +2586,14 @@ Example 1: Simple Two-Agent Workflow ECT Payload: - - - -Nennemann Expires 28 August 2026 [Page 47] - -Internet-Draft WIMSE Execution Context February 2026 - - { "iss": "spiffe://example.com/agent/data-retrieval", "sub": "spiffe://example.com/agent/data-retrieval", "aud": "spiffe://example.com/agent/validator", "iat": 1772064150, "exp": 1772064750, - "jti": "1a2b3c4d-e5f6-7890-abcd-ef0123456701", + "jti": "550e8400-e29b-41d4-a716-446655440001", "wid": "b1c2d3e4-f5a6-7890-bcde-f01234567890", - "tid": "550e8400-e29b-41d4-a716-446655440001", "exec_act": "fetch_patient_data", "par": [], "pol": "clinical_data_access_policy_v1", @@ -2662,9 +2613,8 @@ Internet-Draft WIMSE Execution Context February 2026 "aud": "spiffe://example.com/system/ledger", "iat": 1772064160, "exp": 1772064760, - "jti": "2b3c4d5e-f6a7-8901-bcde-f01234567802", + "jti": "550e8400-e29b-41d4-a716-446655440002", "wid": "b1c2d3e4-f5a6-7890-bcde-f01234567890", - "tid": "550e8400-e29b-41d4-a716-446655440002", "exec_act": "validate_safety", "par": ["550e8400-e29b-41d4-a716-446655440001"], "pol": "safety_validation_policy_v2", @@ -2675,21 +2625,20 @@ Internet-Draft WIMSE Execution Context February 2026 The resulting DAG: + + + + +Nennemann Expires 28 August 2026 [Page 47] + +Internet-Draft WIMSE Execution Context February 2026 + + task-...-0001 (fetch_patient_data) | v task-...-0002 (validate_safety) - - - - - -Nennemann Expires 28 August 2026 [Page 48] - -Internet-Draft WIMSE Execution Context February 2026 - - Example 2: Medical Device SDLC with Release Approval A multi-step medical device software lifecycle workflow with @@ -2703,9 +2652,8 @@ Example 2: Medical Device SDLC with Release Approval "aud": "spiffe://meddev.example/agent/code-gen", "iat": 1772064150, "exp": 1772064750, - "jti": "3c4d5e6f-a7b8-9012-cdef-012345678903", + "jti": "a1b2c3d4-0001-0000-0000-000000000001", "wid": "c2d3e4f5-a6b7-8901-cdef-012345678901", - "tid": "a1b2c3d4-0001-0000-0000-000000000001", "exec_act": "review_requirements_spec", "par": [], "pol": "spec_review_policy_v2", @@ -2724,9 +2672,8 @@ Example 2: Medical Device SDLC with Release Approval "aud": "spiffe://meddev.example/agent/test-runner", "iat": 1772064200, "exp": 1772064800, - "jti": "4d5e6f7a-b8c9-0123-def0-123456789004", + "jti": "a1b2c3d4-0001-0000-0000-000000000002", "wid": "c2d3e4f5-a6b7-8901-cdef-012345678901", - "tid": "a1b2c3d4-0001-0000-0000-000000000002", "exec_act": "implement_module", "par": ["a1b2c3d4-0001-0000-0000-000000000001"], "pol": "coding_standards_v3", @@ -2735,26 +2682,24 @@ Example 2: Medical Device SDLC with Release Approval "model_version": "codegen-v2.4" } - Task 3 (Autonomous Test Agent): - - -Nennemann Expires 28 August 2026 [Page 49] +Nennemann Expires 28 August 2026 [Page 48] Internet-Draft WIMSE Execution Context February 2026 + Task 3 (Autonomous Test Agent): + { "iss": "spiffe://meddev.example/agent/test-runner", "sub": "spiffe://meddev.example/agent/test-runner", "aud": "spiffe://meddev.example/agent/build", "iat": 1772064260, "exp": 1772064860, - "jti": "5e6f7a8b-c9d0-1234-ef01-234567890005", + "jti": "a1b2c3d4-0001-0000-0000-000000000003", "wid": "c2d3e4f5-a6b7-8901-cdef-012345678901", - "tid": "a1b2c3d4-0001-0000-0000-000000000003", "exec_act": "execute_test_suite", "par": ["a1b2c3d4-0001-0000-0000-000000000002"], "pol": "test_coverage_policy_v1", @@ -2771,9 +2716,8 @@ Internet-Draft WIMSE Execution Context February 2026 "aud": "spiffe://meddev.example/human/release-mgr-42", "iat": 1772064310, "exp": 1772064910, - "jti": "6f7a8b9c-d0e1-2345-f012-345678900006", + "jti": "a1b2c3d4-0001-0000-0000-000000000004", "wid": "c2d3e4f5-a6b7-8901-cdef-012345678901", - "tid": "a1b2c3d4-0001-0000-0000-000000000004", "exec_act": "build_release_artifact", "par": ["a1b2c3d4-0001-0000-0000-000000000003"], "pol": "build_validation_v2", @@ -2797,7 +2741,7 @@ Internet-Draft WIMSE Execution Context February 2026 -Nennemann Expires 28 August 2026 [Page 50] +Nennemann Expires 28 August 2026 [Page 49] Internet-Draft WIMSE Execution Context February 2026 @@ -2808,9 +2752,8 @@ Internet-Draft WIMSE Execution Context February 2026 "aud": "spiffe://meddev.example/system/ledger", "iat": 1772064510, "exp": 1772065110, - "jti": "7a8b9c0d-e1f2-3456-0123-456789000007", + "jti": "a1b2c3d4-0001-0000-0000-000000000005", "wid": "c2d3e4f5-a6b7-8901-cdef-012345678901", - "tid": "a1b2c3d4-0001-0000-0000-000000000005", "exec_act": "approve_release", "par": ["a1b2c3d4-0001-0000-0000-000000000004"], "pol": "release_approval_policy", @@ -2847,22 +2790,18 @@ Internet-Draft WIMSE Execution Context February 2026 that the SDLC followed the prescribed process with human oversight at the release gate. - - - - - - -Nennemann Expires 28 August 2026 [Page 51] - -Internet-Draft WIMSE Execution Context February 2026 - - Example 3: Parallel Execution with Join A workflow where two tasks execute in parallel and a third task depends on both: + + +Nennemann Expires 28 August 2026 [Page 50] + +Internet-Draft WIMSE Execution Context February 2026 + + task-...-0001 (assess_risk) | \ v v @@ -2881,9 +2820,8 @@ Example 3: Parallel Execution with Join "aud": "spiffe://bank.example/system/ledger", "iat": 1772064250, "exp": 1772064850, - "jti": "8b9c0d1e-f2a3-4567-1234-567890000008", + "jti": "f1e2d3c4-0004-0000-0000-000000000004", "wid": "d3e4f5a6-b7c8-9012-def0-123456789012", - "tid": "f1e2d3c4-0004-0000-0000-000000000004", "exec_act": "execute_trade", "par": [ "f1e2d3c4-0002-0000-0000-000000000002", @@ -2905,15 +2843,6 @@ Acknowledgments Workload Identity Tokens and Workload Proof Tokens provide the identity foundation upon which execution context tracing is built. - - - - -Nennemann Expires 28 August 2026 [Page 52] - -Internet-Draft WIMSE Execution Context February 2026 - - Author's Address Christian Nennemann @@ -2924,45 +2853,4 @@ Author's Address - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Nennemann Expires 28 August 2026 [Page 53] +Nennemann Expires 28 August 2026 [Page 51] diff --git a/draft-nennemann-wimse-execution-context-00.xml b/draft-nennemann-wimse-execution-context-00.xml index 84ae2a9..a7eb59c 100644 --- a/draft-nennemann-wimse-execution-context-00.xml +++ b/draft-nennemann-wimse-execution-context-00.xml @@ -473,11 +473,15 @@ upon issuance.
      jti:
      - REQUIRED. String. A unique identifier for the ECT in UUID -format . Used for replay detection: receivers MUST -reject ECTs whose "jti" has already been seen within the -expiration window. The "jti" value MUST be unique across all -ECTs issued by the same agent. + REQUIRED. String. A globally unique identifier for both the +ECT and the task it records, in UUID format . Since +each ECT represents exactly one task, "jti" serves as both the +token identifier (for replay detection) and the task identifier +(for DAG parent references in "par"). Receivers MUST reject +ECTs whose "jti" has already been seen within the expiration +window. When "wid" is present, uniqueness is scoped to the +workflow; when "wid" is absent, uniqueness MUST be enforced +globally across the ECT store.
      @@ -491,16 +495,7 @@ ECTs issued by the same agent.
      OPTIONAL. String. A workflow identifier that groups related ECTs into a single workflow. When present, MUST be a UUID -. When absent, the "tid" uniqueness requirement -applies globally across the entire ledger. -
      -
      tid:
      -
      - REQUIRED. String. A globally unique task identifier in UUID -format . Each task MUST have a unique "tid" value. -When "wid" is present, uniqueness is scoped to the workflow; -when "wid" is absent, uniqueness MUST be enforced globally -across the ledger. +.
      exec_act:
      @@ -514,8 +509,8 @@ collision with the "act" (Actor) claim registered by
      par:
      REQUIRED. Array of strings. Parent task identifiers -representing DAG dependencies. Each element MUST be a valid -"tid" from a previously executed task. An empty array indicates +representing DAG dependencies. Each element MUST be the "jti" +value of a previously verified ECT. An empty array indicates a root task with no dependencies. A workflow MAY contain multiple root tasks.
      @@ -529,34 +524,40 @@ multiple root tasks.
      pol:
      - REQUIRED. String. The identifier of the policy rule that was + OPTIONAL. String. The identifier of the policy rule that was evaluated for this task (e.g., -"clinical_data_access_policy_v1"). +"clinical_data_access_policy_v1"). MUST be present when +"pol_decision" is present.
      pol_decision:
      - REQUIRED. String. The result of the policy evaluation. MUST -be one of the values registered in the ECT Policy Decision -Values registry (). Initial values -are: + OPTIONAL. String. The result of the policy evaluation. When +present, MUST be one of the values registered in the ECT Policy +Decision Values registry (). MUST be +present when "pol" is present. Initial values are: "approved": The policy evaluation succeeded and the task was authorized to proceed. "rejected": The policy evaluation failed. A "rejected" ECT -MUST still be appended to the audit ledger for accountability. -An ECT with "pol_decision" of "rejected" MAY appear as a -parent in the "par" array of a subsequent ECT, but only for -compensation, rollback, or remediation tasks. Agents MUST -NOT proceed with normal workflow execution based on a parent -ECT whose "pol_decision" is "rejected". +MUST still be recorded for accountability. An ECT with +"pol_decision" of "rejected" MAY appear as a parent in the +"par" array of a subsequent ECT, but only for compensation, +rollback, or remediation tasks. Agents MUST NOT proceed +with normal workflow execution based on a parent ECT whose +"pol_decision" is "rejected". "pending_human_review": The policy evaluation requires human judgment before proceeding. Agents MUST NOT proceed with dependent tasks until a subsequent ECT from a human reviewer records an "approved" decision referencing this task as a parent. + + When "pol" and "pol_decision" are absent, the ECT records task +execution without a policy checkpoint. Regulated deployments +SHOULD include policy claims on all ECTs to maintain complete +audit trails.
      pol_enforcer:
      @@ -717,10 +718,9 @@ ECTs whose "ext" claim exceeds these limits. "aud": "spiffe://example.com/agent/safety", "iat": 1772064150, "exp": 1772064750, - "jti": "7f3a8b2c-d1e4-4f56-9a0b-c3d4e5f6a7b8", + "jti": "550e8400-e29b-41d4-a716-446655440001", "wid": "a0b1c2d3-e4f5-6789-abcd-ef0123456789", - "tid": "550e8400-e29b-41d4-a716-446655440001", "exec_act": "recommend_treatment", "par": [], @@ -806,10 +806,10 @@ parent ECTs available to the verifier. the following DAG validation steps: - Task ID Uniqueness: The "tid" claim MUST be unique within the + Task ID Uniqueness: The "jti" claim MUST be unique within the applicable scope (the workflow identified by "wid", or the -entire ECT store if "wid" is absent). If a task with the same -"tid" already exists, the ECT MUST be rejected. +entire ECT store if "wid" is absent). If an ECT with the same +"jti" already exists, the ECT MUST be rejected. Parent Existence: Every task identifier listed in the "par" array MUST correspond to a task that is available in the ECT store (either previously recorded in the ledger or received @@ -826,15 +826,17 @@ by the DAG structure (parent existence in the ECT store), not by timestamps. If any parent task violates this constraint, the ECT MUST be rejected. Acyclicity: Following the chain of parent references MUST NOT -lead back to the current task's "tid". If a cycle is detected, +lead back to the current ECT's "jti". If a cycle is detected, the ECT MUST be rejected. - Parent Policy Decision: If any parent task has a "pol_decision" -of "rejected" or "pending_human_review", the current task's -"exec_act" MUST indicate a compensation, rollback, remediation, -or human review action. Implementations MUST NOT accept an ECT -representing normal workflow continuation when a parent's -"pol_decision" is not "approved", unless the current ECT has -"compensation_required" set to true. + Parent Policy Decision: If any parent ECT contains a +"pol_decision" of "rejected" or "pending_human_review", the +current ECT's "exec_act" MUST indicate a compensation, +rollback, remediation, or human review action. +Implementations MUST NOT accept an ECT representing normal +workflow continuation when a parent's "pol_decision" is not +"approved", unless the current ECT has "compensation_required" +set to true. This rule only applies when the parent ECT +contains policy claims. Trust Domain Consistency: Parent tasks SHOULD belong to the same trust domain or to a trust domain with which a federation relationship has been established. @@ -849,8 +851,8 @@ relationship has been established. function validate_dag(ect, ect_store, clock_skew_tolerance): // ect_store: ledger or local cache of verified ECTs // Step 1: Uniqueness check - if ect_store.contains(ect.tid, ect.wid): - return error("Task ID already exists") + 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: @@ -862,26 +864,26 @@ function validate_dag(ect, ect_store, clock_skew_tolerance): // Step 3: Cycle detection (with traversal limit) visited = set() - result = has_cycle(ect.tid, ect.par, ect_store, 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_tid, parent_ids, ect_store, +function has_cycle(target_jti, parent_ids, ect_store, visited, max_depth): if visited.size() >= max_depth: return error("Maximum ancestor traversal limit exceeded") for parent_id in parent_ids: - if parent_id == target_tid: + if parent_id == target_jti: return true if parent_id in visited: continue visited.add(parent_id) parent = ect_store.get(parent_id) if parent is not null: - result = has_cycle(target_tid, parent.par, ect_store, + result = has_cycle(target_jti, parent.par, ect_store, visited, max_depth) if result is error or result is true: return result @@ -939,10 +941,11 @@ identity MUST appear in "aud". 15 minutes) and is not unreasonably far in the future (RECOMMENDED: no more than 30 seconds ahead of the verifier's current time, to account for clock skew). - Verify all required claims ("jti", "tid", "exec_act", "par", -"pol", "pol_decision") are present and well-formed. - Verify "pol_decision" is one of "approved", "rejected", or -"pending_human_review". + Verify all required claims ("jti", "exec_act", "par") are +present and well-formed. + If "pol" or "pol_decision" is present, verify that both are +present and that "pol_decision" is one of "approved", +"rejected", or "pending_human_review". Perform DAG validation per . If all checks pass and an audit ledger is available, the ECT SHOULD be appended to the audit ledger. In point-to-point @@ -1018,15 +1021,17 @@ function verify_ect(ect_jws, verifier_id, return reject("ECT issued in the future") // Verify required claims - for claim in ["jti", "tid", "exec_act", "par", - "pol", "pol_decision"]: + for claim in ["jti", "exec_act", "par"]: if claim not in payload: return reject("Missing required claim: " + claim) - // Validate pol_decision value - if payload.pol_decision not in - ["approved", "rejected", "pending_human_review"]: - return reject("Invalid pol_decision value") + // Validate policy claims (optional, but must be paired) + if "pol" in payload or "pol_decision" in payload: + if "pol" not in payload or "pol_decision" not in payload: + return reject("pol and pol_decision must both be present") + if payload.pol_decision not in + ["approved", "rejected", "pending_human_review"]: + return reject("Invalid pol_decision value") // Validate DAG (against ledger or inline parent ECTs) result = validate_dag(payload, ect_store, @@ -1076,7 +1081,7 @@ available No persistent audit trail unless agents independently retain ECTs Global replay detection relies solely on "jti" caches at each -agent; there is no centralized "tid" uniqueness check +agent; there is no centralized "jti" uniqueness check The parent ECT chain grows with each hop, increasing HTTP header size Post-hoc audit reconstruction requires collecting ECTs from @@ -1141,7 +1146,7 @@ modified or deleted. Ordering: The ledger MUST maintain a total ordering of ECT entries via a monotonically increasing sequence number. Lookup by task ID: The ledger MUST support efficient retrieval -of ECT entries by "tid" value. +of ECT entries by "jti" value. Integrity verification: The ledger SHOULD provide a mechanism to verify that no entries have been tampered with (e.g., hash chains or Merkle trees). @@ -1158,7 +1163,7 @@ workflow agents to reduce the risk of collusion.
      Note: task identifiers in this section are abbreviated for -readability. In production, all "tid" values are required to be +readability. In production, all "jti" values are required to be UUIDs per .
      Medical Device SDLC Workflow @@ -1203,27 +1208,27 @@ software used in medical devices.
      @@ -1334,9 +1339,8 @@ a cryptographic link to the original task: "aud": "spiffe://bank.example/system/ledger", "iat": 1772150550, "exp": 1772151150, - "jti": "e4f5a6b7-c8d9-0123-ef01-234567890abc", + "jti": "550e8400-e29b-41d4-a716-446655440099", "wid": "d3e4f5a6-b7c8-9012-def0-123456789012", - "tid": "550e8400-e29b-41d4-a716-446655440099", "exec_act": "initiate_trade_rollback", "par": ["550e8400-e29b-41d4-a716-446655440003"], "pol": "compensation_policy_v1", @@ -1360,27 +1364,27 @@ required checks were completed:
      @@ -1450,7 +1454,7 @@ attestation ECT: MUST set "iss" to the witness's own workload identity. MUST set "exec_act" to "witness_attestation" (or a domain- specific equivalent). - MUST include the observed task's "tid" in the "par" array, + MUST include the observed task's "jti" in the "par" array, linking the attestation to the original task. MUST set "pol_decision" to "approved" to indicate the witness confirms the observation. @@ -1808,10 +1812,6 @@ the "JSON Web Token Claims" registry maintained by IANA: Workflow Identifier IETF - tid - Task Identifier - IETF - exec_act Action/Task Type IETF @@ -2393,7 +2393,7 @@ been incorporated into this document. This document obsoletes RFC - +
      Related Work @@ -2533,8 +2533,8 @@ use cases are distinct. Create JWTs with all required claims ("iss", "aud", "iat", -"exp", "jti", "tid", "exec_act", "par", "pol", -"pol_decision"). +"exp", "jti", "exec_act", "par") and policy claims ("pol", +"pol_decision") when policy evaluation was performed. Sign ECTs with the agent's private key using an algorithm matching the WIT (ES256 recommended). Verify ECT signatures against WIT public keys. @@ -2641,9 +2641,8 @@ Agent B: "aud": "spiffe://example.com/agent/validator", "iat": 1772064150, "exp": 1772064750, - "jti": "1a2b3c4d-e5f6-7890-abcd-ef0123456701", + "jti": "550e8400-e29b-41d4-a716-446655440001", "wid": "b1c2d3e4-f5a6-7890-bcde-f01234567890", - "tid": "550e8400-e29b-41d4-a716-446655440001", "exec_act": "fetch_patient_data", "par": [], "pol": "clinical_data_access_policy_v1", @@ -2665,9 +2664,8 @@ task, and creates its own ECT: "aud": "spiffe://example.com/system/ledger", "iat": 1772064160, "exp": 1772064760, - "jti": "2b3c4d5e-f6a7-8901-bcde-f01234567802", + "jti": "550e8400-e29b-41d4-a716-446655440002", "wid": "b1c2d3e4-f5a6-7890-bcde-f01234567890", - "tid": "550e8400-e29b-41d4-a716-446655440002", "exec_act": "validate_safety", "par": ["550e8400-e29b-41d4-a716-446655440001"], "pol": "safety_validation_policy_v2", @@ -2701,9 +2699,8 @@ autonomous agents and human release approval: "aud": "spiffe://meddev.example/agent/code-gen", "iat": 1772064150, "exp": 1772064750, - "jti": "3c4d5e6f-a7b8-9012-cdef-012345678903", + "jti": "a1b2c3d4-0001-0000-0000-000000000001", "wid": "c2d3e4f5-a6b7-8901-cdef-012345678901", - "tid": "a1b2c3d4-0001-0000-0000-000000000001", "exec_act": "review_requirements_spec", "par": [], "pol": "spec_review_policy_v2", @@ -2724,9 +2721,8 @@ autonomous agents and human release approval: "aud": "spiffe://meddev.example/agent/test-runner", "iat": 1772064200, "exp": 1772064800, - "jti": "4d5e6f7a-b8c9-0123-def0-123456789004", + "jti": "a1b2c3d4-0001-0000-0000-000000000002", "wid": "c2d3e4f5-a6b7-8901-cdef-012345678901", - "tid": "a1b2c3d4-0001-0000-0000-000000000002", "exec_act": "implement_module", "par": ["a1b2c3d4-0001-0000-0000-000000000001"], "pol": "coding_standards_v3", @@ -2745,9 +2741,8 @@ autonomous agents and human release approval: "aud": "spiffe://meddev.example/agent/build", "iat": 1772064260, "exp": 1772064860, - "jti": "5e6f7a8b-c9d0-1234-ef01-234567890005", + "jti": "a1b2c3d4-0001-0000-0000-000000000003", "wid": "c2d3e4f5-a6b7-8901-cdef-012345678901", - "tid": "a1b2c3d4-0001-0000-0000-000000000003", "exec_act": "execute_test_suite", "par": ["a1b2c3d4-0001-0000-0000-000000000002"], "pol": "test_coverage_policy_v1", @@ -2766,9 +2761,8 @@ autonomous agents and human release approval: "aud": "spiffe://meddev.example/human/release-mgr-42", "iat": 1772064310, "exp": 1772064910, - "jti": "6f7a8b9c-d0e1-2345-f012-345678900006", + "jti": "a1b2c3d4-0001-0000-0000-000000000004", "wid": "c2d3e4f5-a6b7-8901-cdef-012345678901", - "tid": "a1b2c3d4-0001-0000-0000-000000000004", "exec_act": "build_release_artifact", "par": ["a1b2c3d4-0001-0000-0000-000000000003"], "pol": "build_validation_v2", @@ -2787,9 +2781,8 @@ autonomous agents and human release approval: "aud": "spiffe://meddev.example/system/ledger", "iat": 1772064510, "exp": 1772065110, - "jti": "7a8b9c0d-e1f2-3456-0123-456789000007", + "jti": "a1b2c3d4-0001-0000-0000-000000000005", "wid": "c2d3e4f5-a6b7-8901-cdef-012345678901", - "tid": "a1b2c3d4-0001-0000-0000-000000000005", "exec_act": "approve_release", "par": ["a1b2c3d4-0001-0000-0000-000000000004"], "pol": "release_approval_policy", @@ -2856,9 +2849,8 @@ task-...-0004 (execute_trade) "aud": "spiffe://bank.example/system/ledger", "iat": 1772064250, "exp": 1772064850, - "jti": "8b9c0d1e-f2a3-4567-1234-567890000008", + "jti": "f1e2d3c4-0004-0000-0000-000000000004", "wid": "d3e4f5a6-b7c8-9012-def0-123456789012", - "tid": "f1e2d3c4-0004-0000-0000-000000000004", "exec_act": "execute_trade", "par": [ "f1e2d3c4-0002-0000-0000-000000000002", @@ -2890,580 +2882,578 @@ tracing is built.