diff --git a/artifacts/capability_boundary_replay_results.json b/artifacts/capability_boundary_replay_results.json
index cc79107..4b5c7ad 100644
--- a/artifacts/capability_boundary_replay_results.json
+++ b/artifacts/capability_boundary_replay_results.json
@@ -266,9 +266,7 @@
"expected_failure_labels": [
"APPROVAL_GATE_LOSS",
"CAPABILITY_BOUNDARY_LOSS",
- "POLICY_ENFORCEMENT_GAP",
- "RECOVERY_PATH_INVALID",
- "UNAUTHORIZED_CAPABILITY_PATH"
+ "POLICY_ENFORCEMENT_GAP"
],
"capability_boundary": {
"original_edge_count": 4,
@@ -327,11 +325,8 @@
{
"fixture_id": "mcp_trace_replay_mild_v1",
"degradation_level": "mild",
- "expected_admissible": false,
- "expected_failure_labels": [
- "CAPABILITY_BOUNDARY_LOSS",
- "RECOVERY_PATH_INVALID"
- ],
+ "expected_admissible": true,
+ "expected_failure_labels": [],
"capability_boundary": {
"original_edge_count": 4,
"replay_edge_count": 4,
@@ -351,8 +346,8 @@
"degradation_level": "moderate",
"expected_admissible": false,
"expected_failure_labels": [
- "INVARIANT_VIOLATION",
- "UNAUTHORIZED_CAPABILITY_PATH"
+ "APPROVAL_GATE_LOSS",
+ "DEPENDENCY_CHAIN_BREAK"
],
"capability_boundary": {
"original_edge_count": 4,
diff --git a/artifacts/graph_diff_results.json b/artifacts/graph_diff_results.json
index 7db2154..5872700 100644
--- a/artifacts/graph_diff_results.json
+++ b/artifacts/graph_diff_results.json
@@ -1537,9 +1537,7 @@
"expected_failure_labels": [
"APPROVAL_GATE_LOSS",
"CAPABILITY_BOUNDARY_LOSS",
- "POLICY_ENFORCEMENT_GAP",
- "RECOVERY_PATH_INVALID",
- "UNAUTHORIZED_CAPABILITY_PATH"
+ "POLICY_ENFORCEMENT_GAP"
],
"edge_categories": {
"capability_boundaries": {
@@ -1707,11 +1705,8 @@
{
"fixture_id": "mcp_trace_replay_mild_v1",
"degradation_level": "mild",
- "expected_admissible": false,
- "expected_failure_labels": [
- "CAPABILITY_BOUNDARY_LOSS",
- "RECOVERY_PATH_INVALID"
- ],
+ "expected_admissible": true,
+ "expected_failure_labels": [],
"edge_categories": {
"capability_boundaries": {
"original_edge_count": 3,
@@ -1838,8 +1833,8 @@
"degradation_level": "moderate",
"expected_admissible": false,
"expected_failure_labels": [
- "INVARIANT_VIOLATION",
- "UNAUTHORIZED_CAPABILITY_PATH"
+ "APPROVAL_GATE_LOSS",
+ "DEPENDENCY_CHAIN_BREAK"
],
"edge_categories": {
"capability_boundaries": {
diff --git a/artifacts/mcp_trace_replay_results.json b/artifacts/mcp_trace_replay_results.json
index 06f89b3..34de1eb 100644
--- a/artifacts/mcp_trace_replay_results.json
+++ b/artifacts/mcp_trace_replay_results.json
@@ -20,20 +20,17 @@
},
{
"degradation_level": "mild",
- "expected_admissible": false,
- "failed_contracts": [
- "capability_boundary_respected",
- "recovery_path_available"
- ],
- "failure_labels": [
- "CAPABILITY_BOUNDARY_LOSS",
- "RECOVERY_PATH_INVALID"
- ],
+ "expected_admissible": true,
+ "failed_contracts": [],
+ "failure_labels": [],
"fixture_id": "mcp_trace_replay_mild_v1",
- "observed_admissible": false,
- "overall_admissibility_score": "0.833333",
+ "observed_admissible": true,
+ "overall_admissibility_score": "1.000000",
"passed_contracts": [
+ "approval_gate_preserved",
+ "capability_boundary_respected",
"dependency_chain_preserved",
+ "recovery_path_available",
"tool_call_order_preserved",
"validation_before_unsafe_action"
]
@@ -42,17 +39,18 @@
"degradation_level": "moderate",
"expected_admissible": false,
"failed_contracts": [
- "capability_boundary_respected",
+ "approval_gate_preserved",
"dependency_chain_preserved"
],
"failure_labels": [
- "INVARIANT_VIOLATION",
- "UNAUTHORIZED_CAPABILITY_PATH"
+ "APPROVAL_GATE_LOSS",
+ "DEPENDENCY_CHAIN_BREAK"
],
"fixture_id": "mcp_trace_replay_moderate_v1",
"observed_admissible": false,
- "overall_admissibility_score": "0.833333",
+ "overall_admissibility_score": "0.666667",
"passed_contracts": [
+ "capability_boundary_respected",
"recovery_path_available",
"tool_call_order_preserved",
"validation_before_unsafe_action"
@@ -62,23 +60,23 @@
"degradation_level": "severe",
"expected_admissible": false,
"failed_contracts": [
+ "approval_gate_preserved",
"capability_boundary_respected",
- "dependency_chain_preserved",
- "recovery_path_available",
- "tool_call_order_preserved",
"validation_before_unsafe_action"
],
"failure_labels": [
"APPROVAL_GATE_LOSS",
"CAPABILITY_BOUNDARY_LOSS",
- "POLICY_ENFORCEMENT_GAP",
- "RECOVERY_PATH_INVALID",
- "UNAUTHORIZED_CAPABILITY_PATH"
+ "POLICY_ENFORCEMENT_GAP"
],
"fixture_id": "mcp_trace_replay_degraded_v1",
"observed_admissible": false,
- "overall_admissibility_score": "0.500000",
- "passed_contracts": []
+ "overall_admissibility_score": "0.541667",
+ "passed_contracts": [
+ "dependency_chain_preserved",
+ "recovery_path_available",
+ "tool_call_order_preserved"
+ ]
}
],
"generated_by": "McpTraceReplayArtifactGenerator",
diff --git a/artifacts/multi_family_admissibility_curves.svg b/artifacts/multi_family_admissibility_curves.svg
index c84629d..a3e75b1 100644
--- a/artifacts/multi_family_admissibility_curves.svg
+++ b/artifacts/multi_family_admissibility_curves.svg
@@ -38,11 +38,11 @@
incident_response_page_triage
-
+
-
-
-
+
+
+
mcp_trace_replay
diff --git a/artifacts/multi_family_admissibility_results.json b/artifacts/multi_family_admissibility_results.json
index f788ce4..0cd8587 100644
--- a/artifacts/multi_family_admissibility_results.json
+++ b/artifacts/multi_family_admissibility_results.json
@@ -336,80 +336,78 @@
"structural_score": 1.0
},
{
- "expected_admissible": false,
- "failed_contracts": [
- "capability_boundary_respected",
- "recovery_path_available"
- ],
- "failure_labels": [
- "CAPABILITY_BOUNDARY_LOSS",
- "RECOVERY_PATH_INVALID"
- ],
+ "expected_admissible": true,
+ "failed_contracts": [],
+ "failure_labels": [],
"fixture_id": "mcp_trace_replay_mild_v1",
"fixture_path": "fixtures/mcp_trace_replay_mild_v1",
"fixture_version": "1.0.0",
"governance_score": 1.0,
- "observed_admissible": false,
+ "observed_admissible": true,
"operational_score": 1.0,
- "overall_admissibility_score": 0.8333333333333334,
+ "overall_admissibility_score": 1.0,
"passed_contracts": [
+ "approval_gate_preserved",
+ "capability_boundary_respected",
"dependency_chain_preserved",
+ "recovery_path_available",
"tool_call_order_preserved",
"validation_before_unsafe_action"
],
- "relational_score": 0.3333333333333333,
+ "relational_score": 1.0,
"structural_score": 1.0
},
{
"expected_admissible": false,
"failed_contracts": [
- "capability_boundary_respected",
+ "approval_gate_preserved",
"dependency_chain_preserved"
],
"failure_labels": [
- "INVARIANT_VIOLATION",
- "UNAUTHORIZED_CAPABILITY_PATH"
+ "APPROVAL_GATE_LOSS",
+ "DEPENDENCY_CHAIN_BREAK"
],
"fixture_id": "mcp_trace_replay_moderate_v1",
"fixture_path": "fixtures/mcp_trace_replay_moderate_v1",
"fixture_version": "1.0.0",
- "governance_score": 1.0,
+ "governance_score": 0.0,
"observed_admissible": false,
"operational_score": 1.0,
- "overall_admissibility_score": 0.8333333333333334,
+ "overall_admissibility_score": 0.6666666666666666,
"passed_contracts": [
+ "capability_boundary_respected",
"recovery_path_available",
"tool_call_order_preserved",
"validation_before_unsafe_action"
],
- "relational_score": 0.3333333333333333,
+ "relational_score": 0.6666666666666666,
"structural_score": 1.0
},
{
"expected_admissible": false,
"failed_contracts": [
+ "approval_gate_preserved",
"capability_boundary_respected",
- "dependency_chain_preserved",
- "recovery_path_available",
- "tool_call_order_preserved",
"validation_before_unsafe_action"
],
"failure_labels": [
"APPROVAL_GATE_LOSS",
"CAPABILITY_BOUNDARY_LOSS",
- "POLICY_ENFORCEMENT_GAP",
- "RECOVERY_PATH_INVALID",
- "UNAUTHORIZED_CAPABILITY_PATH"
+ "POLICY_ENFORCEMENT_GAP"
],
"fixture_id": "mcp_trace_replay_degraded_v1",
"fixture_path": "fixtures/mcp_trace_replay_degraded_v1",
"fixture_version": "1.0.0",
- "governance_score": 1.0,
+ "governance_score": 0.0,
"observed_admissible": false,
- "operational_score": 0.0,
- "overall_admissibility_score": 0.5,
- "passed_contracts": [],
- "relational_score": 0.0,
+ "operational_score": 0.5,
+ "overall_admissibility_score": 0.5416666666666666,
+ "passed_contracts": [
+ "dependency_chain_preserved",
+ "recovery_path_available",
+ "tool_call_order_preserved"
+ ],
+ "relational_score": 0.6666666666666666,
"structural_score": 1.0
}
],
diff --git a/artifacts/replay_semantic_integrity_results.json b/artifacts/replay_semantic_integrity_results.json
index 172d2b1..7437f55 100644
--- a/artifacts/replay_semantic_integrity_results.json
+++ b/artifacts/replay_semantic_integrity_results.json
@@ -205,43 +205,40 @@
"passed": 3,
"failed": 1,
"failure_labels": [
- "APPROVAL_GATE_LOSS"
+ "POLICY_ENFORCEMENT_GAP"
]
},
"dependencies": {
- "passed": 2,
- "failed": 2,
+ "passed": 3,
+ "failed": 1,
"failure_labels": [
- "UNAUTHORIZED_CAPABILITY_PATH"
+ "DEPENDENCY_CHAIN_BREAK"
]
},
"recovery_paths": {
- "passed": 2,
- "failed": 2,
- "failure_labels": [
- "RECOVERY_PATH_INVALID"
- ]
+ "passed": 4,
+ "failed": 0,
+ "failure_labels": []
},
"tool_order": {
+ "passed": 4,
+ "failed": 0,
+ "failure_labels": []
+ },
+ "capability_boundaries": {
"passed": 3,
"failed": 1,
"failure_labels": [
- "POLICY_ENFORCEMENT_GAP"
+ "CAPABILITY_BOUNDARY_LOSS"
]
},
- "capability_boundaries": {
+ "governance_or_policy": {
"passed": 1,
- "failed": 3,
+ "failed": 2,
"failure_labels": [
- "CAPABILITY_BOUNDARY_LOSS",
- "INVARIANT_VIOLATION"
+ "APPROVAL_GATE_LOSS"
]
},
- "governance_or_policy": {
- "passed": 0,
- "failed": 0,
- "failure_labels": []
- },
"invariants": {
"passed": 0,
"failed": 0,
diff --git a/artifacts/tool_ordering_replay_results.json b/artifacts/tool_ordering_replay_results.json
index d4c768a..685dc4d 100644
--- a/artifacts/tool_ordering_replay_results.json
+++ b/artifacts/tool_ordering_replay_results.json
@@ -278,9 +278,7 @@
"expected_failure_labels": [
"APPROVAL_GATE_LOSS",
"CAPABILITY_BOUNDARY_LOSS",
- "POLICY_ENFORCEMENT_GAP",
- "RECOVERY_PATH_INVALID",
- "UNAUTHORIZED_CAPABILITY_PATH"
+ "POLICY_ENFORCEMENT_GAP"
],
"tool_ordering": {
"original_edge_count": 0,
@@ -298,11 +296,8 @@
{
"fixture_id": "mcp_trace_replay_mild_v1",
"degradation_level": "mild",
- "expected_admissible": false,
- "expected_failure_labels": [
- "CAPABILITY_BOUNDARY_LOSS",
- "RECOVERY_PATH_INVALID"
- ],
+ "expected_admissible": true,
+ "expected_failure_labels": [],
"tool_ordering": {
"original_edge_count": 0,
"replay_edge_count": 0,
@@ -321,8 +316,8 @@
"degradation_level": "moderate",
"expected_admissible": false,
"expected_failure_labels": [
- "INVARIANT_VIOLATION",
- "UNAUTHORIZED_CAPABILITY_PATH"
+ "APPROVAL_GATE_LOSS",
+ "DEPENDENCY_CHAIN_BREAK"
],
"tool_ordering": {
"original_edge_count": 0,
diff --git a/fixtures/manifest.json b/fixtures/manifest.json
index 2d57d28..dbf21f8 100644
--- a/fixtures/manifest.json
+++ b/fixtures/manifest.json
@@ -248,18 +248,16 @@
"family": "mcp_trace_replay",
"degradation_level": "mild",
"path": "fixtures/mcp_trace_replay_mild_v1",
- "expected_admissible": false,
+ "expected_admissible": true,
"contracts": [
+ "approval_gate_preserved",
"capability_boundary_respected",
"dependency_chain_preserved",
"recovery_path_available",
"tool_call_order_preserved",
"validation_before_unsafe_action"
],
- "expected_failure_labels": [
- "CAPABILITY_BOUNDARY_LOSS",
- "RECOVERY_PATH_INVALID"
- ]
+ "expected_failure_labels": []
},
{
"fixture_id": "mcp_trace_replay_moderate_v1",
@@ -270,6 +268,7 @@
"path": "fixtures/mcp_trace_replay_moderate_v1",
"expected_admissible": false,
"contracts": [
+ "approval_gate_preserved",
"capability_boundary_respected",
"dependency_chain_preserved",
"recovery_path_available",
@@ -277,8 +276,8 @@
"validation_before_unsafe_action"
],
"expected_failure_labels": [
- "INVARIANT_VIOLATION",
- "UNAUTHORIZED_CAPABILITY_PATH"
+ "APPROVAL_GATE_LOSS",
+ "DEPENDENCY_CHAIN_BREAK"
]
},
{
@@ -290,6 +289,7 @@
"path": "fixtures/mcp_trace_replay_degraded_v1",
"expected_admissible": false,
"contracts": [
+ "approval_gate_preserved",
"capability_boundary_respected",
"dependency_chain_preserved",
"recovery_path_available",
@@ -299,9 +299,7 @@
"expected_failure_labels": [
"APPROVAL_GATE_LOSS",
"CAPABILITY_BOUNDARY_LOSS",
- "POLICY_ENFORCEMENT_GAP",
- "RECOVERY_PATH_INVALID",
- "UNAUTHORIZED_CAPABILITY_PATH"
+ "POLICY_ENFORCEMENT_GAP"
]
}
]
diff --git a/fixtures/mcp_trace_replay_degraded_v1/expected/admissibility.json b/fixtures/mcp_trace_replay_degraded_v1/expected/admissibility.json
index b3de76c..fa16a6a 100644
--- a/fixtures/mcp_trace_replay_degraded_v1/expected/admissibility.json
+++ b/fixtures/mcp_trace_replay_degraded_v1/expected/admissibility.json
@@ -12,8 +12,6 @@
"expected_failure_labels": [
"APPROVAL_GATE_LOSS",
"CAPABILITY_BOUNDARY_LOSS",
- "POLICY_ENFORCEMENT_GAP",
- "RECOVERY_PATH_INVALID",
- "UNAUTHORIZED_CAPABILITY_PATH"
+ "POLICY_ENFORCEMENT_GAP"
]
}
diff --git a/fixtures/mcp_trace_replay_degraded_v1/expected/failures.json b/fixtures/mcp_trace_replay_degraded_v1/expected/failures.json
index c5a5ba2..0ca73c7 100644
--- a/fixtures/mcp_trace_replay_degraded_v1/expected/failures.json
+++ b/fixtures/mcp_trace_replay_degraded_v1/expected/failures.json
@@ -2,9 +2,7 @@
"expected_failures": [
"APPROVAL_GATE_LOSS",
"CAPABILITY_BOUNDARY_LOSS",
- "POLICY_ENFORCEMENT_GAP",
- "RECOVERY_PATH_INVALID",
- "UNAUTHORIZED_CAPABILITY_PATH"
+ "POLICY_ENFORCEMENT_GAP"
],
"allowed_failures": [
"ORPHAN_DEPENDENCY",
diff --git a/fixtures/mcp_trace_replay_degraded_v1/original/contracts/approval_gate_preserved.json b/fixtures/mcp_trace_replay_degraded_v1/original/contracts/approval_gate_preserved.json
new file mode 100644
index 0000000..f062739
--- /dev/null
+++ b/fixtures/mcp_trace_replay_degraded_v1/original/contracts/approval_gate_preserved.json
@@ -0,0 +1,16 @@
+{
+ "contract_id": "approval_gate_preserved",
+ "layer": "governance",
+ "type": "invariant",
+ "definition": {
+ "rule": "required_boundaries_preserved",
+ "required_boundaries": [
+ [
+ "human_approval",
+ "execute_external_action"
+ ]
+ ]
+ },
+ "severity": "CRITICAL",
+ "failure_label_on_violation": "APPROVAL_GATE_LOSS"
+}
diff --git a/fixtures/mcp_trace_replay_degraded_v1/original/contracts/capability_boundary_respected.json b/fixtures/mcp_trace_replay_degraded_v1/original/contracts/capability_boundary_respected.json
index 5b1a9b5..c996f49 100644
--- a/fixtures/mcp_trace_replay_degraded_v1/original/contracts/capability_boundary_respected.json
+++ b/fixtures/mcp_trace_replay_degraded_v1/original/contracts/capability_boundary_respected.json
@@ -3,7 +3,13 @@
"layer": "relational",
"type": "invariant",
"definition": {
- "rule": "no_orphan_dependencies"
+ "rule": "required_boundaries_preserved",
+ "required_boundaries": [
+ [
+ "capability_scope_checked",
+ "validate_external_action"
+ ]
+ ]
},
"severity": "HIGH",
"failure_label_on_violation": "CAPABILITY_BOUNDARY_LOSS"
diff --git a/fixtures/mcp_trace_replay_degraded_v1/original/contracts/dependency_chain_preserved.json b/fixtures/mcp_trace_replay_degraded_v1/original/contracts/dependency_chain_preserved.json
index 6729d2d..962ad96 100644
--- a/fixtures/mcp_trace_replay_degraded_v1/original/contracts/dependency_chain_preserved.json
+++ b/fixtures/mcp_trace_replay_degraded_v1/original/contracts/dependency_chain_preserved.json
@@ -1,23 +1,16 @@
{
"contract_id": "dependency_chain_preserved",
"layer": "relational",
- "type": "causality",
+ "type": "invariant",
"definition": {
- "required_causal_edges": [
+ "rule": "required_dependency_edges_preserved",
+ "required_edges": [
[
- "capability_scope_checked",
+ "read_context",
"validate_external_action"
- ],
- [
- "validate_external_action",
- "execute_external_action"
- ],
- [
- "execute_external_action",
- "verify_result"
]
]
},
"severity": "HIGH",
- "failure_label_on_violation": "UNAUTHORIZED_CAPABILITY_PATH"
+ "failure_label_on_violation": "DEPENDENCY_CHAIN_BREAK"
}
diff --git a/fixtures/mcp_trace_replay_degraded_v1/original/contracts/recovery_path_available.json b/fixtures/mcp_trace_replay_degraded_v1/original/contracts/recovery_path_available.json
index eb3ac8a..8ed9bb2 100644
--- a/fixtures/mcp_trace_replay_degraded_v1/original/contracts/recovery_path_available.json
+++ b/fixtures/mcp_trace_replay_degraded_v1/original/contracts/recovery_path_available.json
@@ -1,13 +1,15 @@
{
"contract_id": "recovery_path_available",
"layer": "relational",
- "type": "reachability",
+ "type": "ordering",
"definition": {
- "from": "execute_external_action",
- "to": [
+ "required_sequence": [
+ "execute_external_action",
"recovery_path_registered"
],
- "min_paths": 1
+ "rule": "required_terminal_action_preserved",
+ "terminal_action": "recovery_path_registered"
},
- "severity": "HIGH"
+ "severity": "HIGH",
+ "failure_label_on_violation": "RECOVERY_PATH_INVALID"
}
diff --git a/fixtures/mcp_trace_replay_degraded_v1/original/contracts/tool_call_order_preserved.json b/fixtures/mcp_trace_replay_degraded_v1/original/contracts/tool_call_order_preserved.json
index d46ae6f..5ccf326 100644
--- a/fixtures/mcp_trace_replay_degraded_v1/original/contracts/tool_call_order_preserved.json
+++ b/fixtures/mcp_trace_replay_degraded_v1/original/contracts/tool_call_order_preserved.json
@@ -4,14 +4,11 @@
"type": "ordering",
"definition": {
"required_sequence": [
- "capability_scope_checked",
"tool_schema_validated",
- "read_context",
- "validate_external_action",
- "execute_external_action",
- "verify_result"
- ]
+ "read_context"
+ ],
+ "rule": "required_action_order_preserved"
},
"severity": "CRITICAL",
- "failure_label_on_violation": "POLICY_ENFORCEMENT_GAP"
+ "failure_label_on_violation": "TOOL_ORDER_VIOLATION"
}
diff --git a/fixtures/mcp_trace_replay_degraded_v1/original/contracts/validation_before_unsafe_action.json b/fixtures/mcp_trace_replay_degraded_v1/original/contracts/validation_before_unsafe_action.json
index 27ef6d2..b1572de 100644
--- a/fixtures/mcp_trace_replay_degraded_v1/original/contracts/validation_before_unsafe_action.json
+++ b/fixtures/mcp_trace_replay_degraded_v1/original/contracts/validation_before_unsafe_action.json
@@ -9,5 +9,5 @@
]
},
"severity": "CRITICAL",
- "failure_label_on_violation": "APPROVAL_GATE_LOSS"
+ "failure_label_on_violation": "POLICY_ENFORCEMENT_GAP"
}
diff --git a/fixtures/mcp_trace_replay_mild_v1/expected/admissibility.json b/fixtures/mcp_trace_replay_mild_v1/expected/admissibility.json
index 1c34a71..0897493 100644
--- a/fixtures/mcp_trace_replay_mild_v1/expected/admissibility.json
+++ b/fixtures/mcp_trace_replay_mild_v1/expected/admissibility.json
@@ -1,13 +1,10 @@
{
"fixture_id": "mcp_trace_replay_mild_v1",
"fixture_version": "1.0.0",
- "expected_admissible": false,
+ "expected_admissible": true,
"must_fail_contracts": [
"capability_boundary_respected",
"recovery_path_available"
],
- "expected_failure_labels": [
- "CAPABILITY_BOUNDARY_LOSS",
- "RECOVERY_PATH_INVALID"
- ]
+ "expected_failure_labels": []
}
diff --git a/fixtures/mcp_trace_replay_mild_v1/expected/failures.json b/fixtures/mcp_trace_replay_mild_v1/expected/failures.json
index 1f9bea6..39a2d14 100644
--- a/fixtures/mcp_trace_replay_mild_v1/expected/failures.json
+++ b/fixtures/mcp_trace_replay_mild_v1/expected/failures.json
@@ -1,8 +1,5 @@
{
- "expected_failures": [
- "CAPABILITY_BOUNDARY_LOSS",
- "RECOVERY_PATH_INVALID"
- ],
+ "expected_failures": [],
"allowed_failures": [
"ORPHAN_DEPENDENCY",
"DETACHED_DEPENDENCY",
diff --git a/fixtures/mcp_trace_replay_mild_v1/original/contracts/approval_gate_preserved.json b/fixtures/mcp_trace_replay_mild_v1/original/contracts/approval_gate_preserved.json
new file mode 100644
index 0000000..f062739
--- /dev/null
+++ b/fixtures/mcp_trace_replay_mild_v1/original/contracts/approval_gate_preserved.json
@@ -0,0 +1,16 @@
+{
+ "contract_id": "approval_gate_preserved",
+ "layer": "governance",
+ "type": "invariant",
+ "definition": {
+ "rule": "required_boundaries_preserved",
+ "required_boundaries": [
+ [
+ "human_approval",
+ "execute_external_action"
+ ]
+ ]
+ },
+ "severity": "CRITICAL",
+ "failure_label_on_violation": "APPROVAL_GATE_LOSS"
+}
diff --git a/fixtures/mcp_trace_replay_mild_v1/original/contracts/capability_boundary_respected.json b/fixtures/mcp_trace_replay_mild_v1/original/contracts/capability_boundary_respected.json
index 5b1a9b5..c996f49 100644
--- a/fixtures/mcp_trace_replay_mild_v1/original/contracts/capability_boundary_respected.json
+++ b/fixtures/mcp_trace_replay_mild_v1/original/contracts/capability_boundary_respected.json
@@ -3,7 +3,13 @@
"layer": "relational",
"type": "invariant",
"definition": {
- "rule": "no_orphan_dependencies"
+ "rule": "required_boundaries_preserved",
+ "required_boundaries": [
+ [
+ "capability_scope_checked",
+ "validate_external_action"
+ ]
+ ]
},
"severity": "HIGH",
"failure_label_on_violation": "CAPABILITY_BOUNDARY_LOSS"
diff --git a/fixtures/mcp_trace_replay_mild_v1/original/contracts/dependency_chain_preserved.json b/fixtures/mcp_trace_replay_mild_v1/original/contracts/dependency_chain_preserved.json
index 155afe2..962ad96 100644
--- a/fixtures/mcp_trace_replay_mild_v1/original/contracts/dependency_chain_preserved.json
+++ b/fixtures/mcp_trace_replay_mild_v1/original/contracts/dependency_chain_preserved.json
@@ -1,22 +1,16 @@
{
"contract_id": "dependency_chain_preserved",
"layer": "relational",
- "type": "causality",
+ "type": "invariant",
"definition": {
- "required_causal_edges": [
+ "rule": "required_dependency_edges_preserved",
+ "required_edges": [
[
- "capability_scope_checked",
+ "read_context",
"validate_external_action"
- ],
- [
- "validate_external_action",
- "execute_external_action"
- ],
- [
- "execute_external_action",
- "verify_result"
]
]
},
- "severity": "HIGH"
+ "severity": "HIGH",
+ "failure_label_on_violation": "DEPENDENCY_CHAIN_BREAK"
}
diff --git a/fixtures/mcp_trace_replay_mild_v1/original/contracts/recovery_path_available.json b/fixtures/mcp_trace_replay_mild_v1/original/contracts/recovery_path_available.json
index eb3ac8a..8ed9bb2 100644
--- a/fixtures/mcp_trace_replay_mild_v1/original/contracts/recovery_path_available.json
+++ b/fixtures/mcp_trace_replay_mild_v1/original/contracts/recovery_path_available.json
@@ -1,13 +1,15 @@
{
"contract_id": "recovery_path_available",
"layer": "relational",
- "type": "reachability",
+ "type": "ordering",
"definition": {
- "from": "execute_external_action",
- "to": [
+ "required_sequence": [
+ "execute_external_action",
"recovery_path_registered"
],
- "min_paths": 1
+ "rule": "required_terminal_action_preserved",
+ "terminal_action": "recovery_path_registered"
},
- "severity": "HIGH"
+ "severity": "HIGH",
+ "failure_label_on_violation": "RECOVERY_PATH_INVALID"
}
diff --git a/fixtures/mcp_trace_replay_mild_v1/original/contracts/tool_call_order_preserved.json b/fixtures/mcp_trace_replay_mild_v1/original/contracts/tool_call_order_preserved.json
index d9468cb..5ccf326 100644
--- a/fixtures/mcp_trace_replay_mild_v1/original/contracts/tool_call_order_preserved.json
+++ b/fixtures/mcp_trace_replay_mild_v1/original/contracts/tool_call_order_preserved.json
@@ -4,13 +4,11 @@
"type": "ordering",
"definition": {
"required_sequence": [
- "capability_scope_checked",
"tool_schema_validated",
- "read_context",
- "validate_external_action",
- "execute_external_action",
- "verify_result"
- ]
+ "read_context"
+ ],
+ "rule": "required_action_order_preserved"
},
- "severity": "CRITICAL"
+ "severity": "CRITICAL",
+ "failure_label_on_violation": "TOOL_ORDER_VIOLATION"
}
diff --git a/fixtures/mcp_trace_replay_mild_v1/original/contracts/validation_before_unsafe_action.json b/fixtures/mcp_trace_replay_mild_v1/original/contracts/validation_before_unsafe_action.json
index f637b94..b1572de 100644
--- a/fixtures/mcp_trace_replay_mild_v1/original/contracts/validation_before_unsafe_action.json
+++ b/fixtures/mcp_trace_replay_mild_v1/original/contracts/validation_before_unsafe_action.json
@@ -8,5 +8,6 @@
"execute_external_action"
]
},
- "severity": "CRITICAL"
+ "severity": "CRITICAL",
+ "failure_label_on_violation": "POLICY_ENFORCEMENT_GAP"
}
diff --git a/fixtures/mcp_trace_replay_moderate_v1/expected/admissibility.json b/fixtures/mcp_trace_replay_moderate_v1/expected/admissibility.json
index a998b0d..df467a1 100644
--- a/fixtures/mcp_trace_replay_moderate_v1/expected/admissibility.json
+++ b/fixtures/mcp_trace_replay_moderate_v1/expected/admissibility.json
@@ -7,7 +7,7 @@
"capability_boundary_respected"
],
"expected_failure_labels": [
- "INVARIANT_VIOLATION",
- "UNAUTHORIZED_CAPABILITY_PATH"
+ "APPROVAL_GATE_LOSS",
+ "DEPENDENCY_CHAIN_BREAK"
]
}
diff --git a/fixtures/mcp_trace_replay_moderate_v1/expected/failures.json b/fixtures/mcp_trace_replay_moderate_v1/expected/failures.json
index 29b223f..0af3044 100644
--- a/fixtures/mcp_trace_replay_moderate_v1/expected/failures.json
+++ b/fixtures/mcp_trace_replay_moderate_v1/expected/failures.json
@@ -1,7 +1,7 @@
{
"expected_failures": [
- "INVARIANT_VIOLATION",
- "UNAUTHORIZED_CAPABILITY_PATH"
+ "APPROVAL_GATE_LOSS",
+ "DEPENDENCY_CHAIN_BREAK"
],
"allowed_failures": [
"ORPHAN_DEPENDENCY",
diff --git a/fixtures/mcp_trace_replay_moderate_v1/original/contracts/approval_gate_preserved.json b/fixtures/mcp_trace_replay_moderate_v1/original/contracts/approval_gate_preserved.json
new file mode 100644
index 0000000..f062739
--- /dev/null
+++ b/fixtures/mcp_trace_replay_moderate_v1/original/contracts/approval_gate_preserved.json
@@ -0,0 +1,16 @@
+{
+ "contract_id": "approval_gate_preserved",
+ "layer": "governance",
+ "type": "invariant",
+ "definition": {
+ "rule": "required_boundaries_preserved",
+ "required_boundaries": [
+ [
+ "human_approval",
+ "execute_external_action"
+ ]
+ ]
+ },
+ "severity": "CRITICAL",
+ "failure_label_on_violation": "APPROVAL_GATE_LOSS"
+}
diff --git a/fixtures/mcp_trace_replay_moderate_v1/original/contracts/capability_boundary_respected.json b/fixtures/mcp_trace_replay_moderate_v1/original/contracts/capability_boundary_respected.json
index f10b6e4..c996f49 100644
--- a/fixtures/mcp_trace_replay_moderate_v1/original/contracts/capability_boundary_respected.json
+++ b/fixtures/mcp_trace_replay_moderate_v1/original/contracts/capability_boundary_respected.json
@@ -3,7 +3,14 @@
"layer": "relational",
"type": "invariant",
"definition": {
- "rule": "no_orphan_dependencies"
+ "rule": "required_boundaries_preserved",
+ "required_boundaries": [
+ [
+ "capability_scope_checked",
+ "validate_external_action"
+ ]
+ ]
},
- "severity": "HIGH"
+ "severity": "HIGH",
+ "failure_label_on_violation": "CAPABILITY_BOUNDARY_LOSS"
}
diff --git a/fixtures/mcp_trace_replay_moderate_v1/original/contracts/dependency_chain_preserved.json b/fixtures/mcp_trace_replay_moderate_v1/original/contracts/dependency_chain_preserved.json
index 6729d2d..962ad96 100644
--- a/fixtures/mcp_trace_replay_moderate_v1/original/contracts/dependency_chain_preserved.json
+++ b/fixtures/mcp_trace_replay_moderate_v1/original/contracts/dependency_chain_preserved.json
@@ -1,23 +1,16 @@
{
"contract_id": "dependency_chain_preserved",
"layer": "relational",
- "type": "causality",
+ "type": "invariant",
"definition": {
- "required_causal_edges": [
+ "rule": "required_dependency_edges_preserved",
+ "required_edges": [
[
- "capability_scope_checked",
+ "read_context",
"validate_external_action"
- ],
- [
- "validate_external_action",
- "execute_external_action"
- ],
- [
- "execute_external_action",
- "verify_result"
]
]
},
"severity": "HIGH",
- "failure_label_on_violation": "UNAUTHORIZED_CAPABILITY_PATH"
+ "failure_label_on_violation": "DEPENDENCY_CHAIN_BREAK"
}
diff --git a/fixtures/mcp_trace_replay_moderate_v1/original/contracts/recovery_path_available.json b/fixtures/mcp_trace_replay_moderate_v1/original/contracts/recovery_path_available.json
index eb3ac8a..8ed9bb2 100644
--- a/fixtures/mcp_trace_replay_moderate_v1/original/contracts/recovery_path_available.json
+++ b/fixtures/mcp_trace_replay_moderate_v1/original/contracts/recovery_path_available.json
@@ -1,13 +1,15 @@
{
"contract_id": "recovery_path_available",
"layer": "relational",
- "type": "reachability",
+ "type": "ordering",
"definition": {
- "from": "execute_external_action",
- "to": [
+ "required_sequence": [
+ "execute_external_action",
"recovery_path_registered"
],
- "min_paths": 1
+ "rule": "required_terminal_action_preserved",
+ "terminal_action": "recovery_path_registered"
},
- "severity": "HIGH"
+ "severity": "HIGH",
+ "failure_label_on_violation": "RECOVERY_PATH_INVALID"
}
diff --git a/fixtures/mcp_trace_replay_moderate_v1/original/contracts/tool_call_order_preserved.json b/fixtures/mcp_trace_replay_moderate_v1/original/contracts/tool_call_order_preserved.json
index d9468cb..5ccf326 100644
--- a/fixtures/mcp_trace_replay_moderate_v1/original/contracts/tool_call_order_preserved.json
+++ b/fixtures/mcp_trace_replay_moderate_v1/original/contracts/tool_call_order_preserved.json
@@ -4,13 +4,11 @@
"type": "ordering",
"definition": {
"required_sequence": [
- "capability_scope_checked",
"tool_schema_validated",
- "read_context",
- "validate_external_action",
- "execute_external_action",
- "verify_result"
- ]
+ "read_context"
+ ],
+ "rule": "required_action_order_preserved"
},
- "severity": "CRITICAL"
+ "severity": "CRITICAL",
+ "failure_label_on_violation": "TOOL_ORDER_VIOLATION"
}
diff --git a/fixtures/mcp_trace_replay_moderate_v1/original/contracts/validation_before_unsafe_action.json b/fixtures/mcp_trace_replay_moderate_v1/original/contracts/validation_before_unsafe_action.json
index f637b94..b1572de 100644
--- a/fixtures/mcp_trace_replay_moderate_v1/original/contracts/validation_before_unsafe_action.json
+++ b/fixtures/mcp_trace_replay_moderate_v1/original/contracts/validation_before_unsafe_action.json
@@ -8,5 +8,6 @@
"execute_external_action"
]
},
- "severity": "CRITICAL"
+ "severity": "CRITICAL",
+ "failure_label_on_violation": "POLICY_ENFORCEMENT_GAP"
}
diff --git a/src/validation/contract_validator.py b/src/validation/contract_validator.py
index 94d9ac7..8f1d335 100644
--- a/src/validation/contract_validator.py
+++ b/src/validation/contract_validator.py
@@ -142,7 +142,13 @@ def _validate_ordering(self, contract_id: str, layer: Layer, severity: str, defi
raise ContractValidationError(f"contract '{contract_id}' requires definition.required_sequence as list[str]")
observed_sequence = self._extract_observed_actions(reconstructed)
+ terminal_action = definition.get("terminal_action")
+ if terminal_action is not None and not isinstance(terminal_action, str):
+ raise ContractValidationError(f"contract '{contract_id}' requires definition.terminal_action as string when provided")
+
passed = self._is_ordered_subsequence(required_sequence, observed_sequence)
+ terminal_mismatch = bool(terminal_action) and (len(observed_sequence) == 0 or observed_sequence[-1] != terminal_action)
+ passed = passed and not terminal_mismatch
return ValidationResult(
contract_id=contract_id,
layer=layer,
@@ -262,22 +268,57 @@ def _validate_causality(self, contract_id: str, layer: Layer, severity: str, def
def _validate_invariant(self, contract_id: str, layer: Layer, severity: str, definition: dict[str, Any], original: dict[str, Any], reconstructed: dict[str, Any], failure_label_on_violation: Any) -> ValidationResult:
rule = definition.get("rule")
- if rule != "no_orphan_dependencies":
- raise ContractValidationError(f"contract '{contract_id}' supports only invariant rule 'no_orphan_dependencies'")
-
- original_graph = self._extract_graph(original, "original")
- reconstructed_graph = self._extract_graph(reconstructed, "reconstructed")
- comparison = DependencyGraphComparator().compare(original_graph, reconstructed_graph)
- metrics, labels = self._comparison_summary(comparison)
+ if rule == "no_orphan_dependencies":
+ original_graph = self._extract_graph(original, "original")
+ reconstructed_graph = self._extract_graph(reconstructed, "reconstructed")
+ comparison = DependencyGraphComparator().compare(original_graph, reconstructed_graph)
+ metrics, labels = self._comparison_summary(comparison)
- passed = "ORPHAN_DEPENDENCY" not in labels
- return ValidationResult(
- contract_id=contract_id,
- layer=layer,
- contract_type=ContractType.INVARIANT,
- passed=passed,
- severity=severity,
- failure_label=None if passed else failure_label_on_violation or "INVARIANT_VIOLATION",
- invariant_category=None if passed else "reachability",
- deterministic_evidence={"rule": rule, "comparator_metrics": metrics, "comparator_failure_labels": labels},
- )
+ passed = "ORPHAN_DEPENDENCY" not in labels
+ return ValidationResult(
+ contract_id=contract_id,
+ layer=layer,
+ contract_type=ContractType.INVARIANT,
+ passed=passed,
+ severity=severity,
+ failure_label=None if passed else failure_label_on_violation or "INVARIANT_VIOLATION",
+ invariant_category=None if passed else "reachability",
+ deterministic_evidence={"rule": rule, "comparator_metrics": metrics, "comparator_failure_labels": labels},
+ )
+
+ if rule == "required_boundaries_preserved":
+ required_boundaries = definition.get("required_boundaries")
+ if required_boundaries is None:
+ required_boundaries = []
+ if not isinstance(required_boundaries, list):
+ raise RuntimeError(f"contract '{contract_id}' requires definition.required_boundaries as list")
+ state = reconstructed.get("state", reconstructed)
+ boundaries = state.get("capability_boundaries") if isinstance(state, dict) else []
+ if boundaries is None:
+ boundaries = []
+ if not isinstance(boundaries, list):
+ raise RuntimeError(f"contract '{contract_id}' requires reconstructed capability_boundaries as list")
+ normalized = [tuple(x) for x in required_boundaries if isinstance(x, list) and len(x) == 2 and all(isinstance(i, str) and i for i in x)]
+ if len(normalized) != len(required_boundaries):
+ raise ContractValidationError(f"contract '{contract_id}' has invalid required boundary entry")
+ present = {tuple(x) for x in boundaries if isinstance(x, list) and len(x) == 2}
+ missing = sorted([list(edge) for edge in normalized if edge not in present])
+ passed = len(missing) == 0
+ return ValidationResult(contract_id=contract_id, layer=layer, contract_type=ContractType.INVARIANT, passed=passed, severity=severity, failure_label=None if passed else failure_label_on_violation or "CAPABILITY_BOUNDARY_LOSS", invariant_category=None if passed else "boundaries", deterministic_evidence={"rule": rule, "required_boundaries": [list(e) for e in normalized], "missing_boundaries": missing})
+
+ if rule == "required_dependency_edges_preserved":
+ required_edges = definition.get("required_edges")
+ if required_edges is None:
+ required_edges = []
+ if not isinstance(required_edges, list):
+ raise RuntimeError(f"contract '{contract_id}' requires definition.required_edges as list")
+ graph = self._extract_graph(reconstructed, "reconstructed")
+ present = {(e.source, e.target) for e in graph.get_edges()}
+ normalized = [tuple(x) for x in required_edges if isinstance(x, list) and len(x) == 2 and all(isinstance(i, str) and i for i in x)]
+ if len(normalized) != len(required_edges):
+ raise ContractValidationError(f"contract '{contract_id}' has invalid required edge entry")
+ missing = sorted([list(edge) for edge in normalized if edge not in present])
+ passed = len(missing) == 0
+ return ValidationResult(contract_id=contract_id, layer=layer, contract_type=ContractType.INVARIANT, passed=passed, severity=severity, failure_label=None if passed else failure_label_on_violation or "DEPENDENCY_CHAIN_BREAK", invariant_category=None if passed else "dependencies", deterministic_evidence={"rule": rule, "required_edges": [list(e) for e in normalized], "missing_edges": missing})
+
+ raise ContractValidationError(f"contract '{contract_id}' has unsupported invariant rule: {rule}")
diff --git a/tests/test_capability_boundary_replay_artifact.py b/tests/test_capability_boundary_replay_artifact.py
index f498438..03b928a 100644
--- a/tests/test_capability_boundary_replay_artifact.py
+++ b/tests/test_capability_boundary_replay_artifact.py
@@ -17,6 +17,7 @@
"UNAUTHORIZED_CAPABILITY_PATH",
"APPROVAL_GATE_LOSS",
"POLICY_ENFORCEMENT_GAP",
+ "DEPENDENCY_CHAIN_BREAK",
}
diff --git a/tests/test_contract_validator.py b/tests/test_contract_validator.py
index 43a47d6..7c8bdc9 100644
--- a/tests/test_contract_validator.py
+++ b/tests/test_contract_validator.py
@@ -294,3 +294,126 @@ def test_relational_contract_evidence_contains_comparator_metrics() -> None:
"causal_preservation_score",
"temporal_order_violation_rate",
}
+
+
+def test_invariant_required_boundaries_preserved_emits_configured_label_when_boundary_missing() -> None:
+ contract = {
+ "contract_id": "capability_boundary_respected",
+ "layer": "governance",
+ "type": "invariant",
+ "definition": {
+ "rule": "required_boundaries_preserved",
+ "required_boundaries": [["human_approval", "execute_external_action"]],
+ },
+ "severity": "CRITICAL",
+ "failure_label_on_violation": "APPROVAL_GATE_LOSS",
+ }
+ reconstructed = {"state": {"capability_boundaries": []}}
+
+ result = ContractValidator().validate_contract({}, reconstructed, contract)
+
+ assert result.passed is False
+ assert result.failure_label == "APPROVAL_GATE_LOSS"
+ assert result.deterministic_evidence["missing_boundaries"] == [["human_approval", "execute_external_action"]]
+
+
+def test_invariant_required_dependency_edges_preserved_emits_configured_label_when_edge_missing() -> None:
+ contract = {
+ "contract_id": "dependency_chain_preserved",
+ "layer": "relational",
+ "type": "invariant",
+ "definition": {
+ "rule": "required_dependency_edges_preserved",
+ "required_edges": [["read_context", "validate_external_action"]],
+ },
+ "severity": "HIGH",
+ "failure_label_on_violation": "DEPENDENCY_CHAIN_BREAK",
+ }
+ reconstructed = {
+ "dependency_graph": _graph_payload(
+ ["read_context", "validate_external_action"],
+ [],
+ )
+ }
+
+ result = ContractValidator().validate_contract({}, reconstructed, contract)
+
+ assert result.passed is False
+ assert result.failure_label == "DEPENDENCY_CHAIN_BREAK"
+ assert result.deterministic_evidence["missing_edges"] == [["read_context", "validate_external_action"]]
+
+
+def test_invariant_required_boundaries_preserved_treats_null_lists_as_empty() -> None:
+ contract = {
+ "contract_id": "capability_boundary_respected",
+ "layer": "governance",
+ "type": "invariant",
+ "definition": {
+ "rule": "required_boundaries_preserved",
+ "required_boundaries": None,
+ },
+ "severity": "CRITICAL",
+ }
+ reconstructed = {"state": {"capability_boundaries": None}}
+
+ result = ContractValidator().validate_contract({}, reconstructed, contract)
+
+ assert result.passed is True
+ assert result.failure_label is None
+
+
+def test_invariant_required_dependency_edges_preserved_treats_null_list_as_empty() -> None:
+ contract = {
+ "contract_id": "dependency_chain_preserved",
+ "layer": "relational",
+ "type": "invariant",
+ "definition": {
+ "rule": "required_dependency_edges_preserved",
+ "required_edges": None,
+ },
+ "severity": "HIGH",
+ }
+ reconstructed = {
+ "dependency_graph": _graph_payload(["read_context", "validate_external_action"], []),
+ }
+
+ result = ContractValidator().validate_contract({}, reconstructed, contract)
+
+ assert result.passed is True
+ assert result.failure_label is None
+
+
+def test_invariant_required_lists_reject_non_list_values() -> None:
+ bad_boundaries = {
+ "contract_id": "capability_boundary_respected",
+ "layer": "governance",
+ "type": "invariant",
+ "definition": {"rule": "required_boundaries_preserved", "required_boundaries": "not-a-list"},
+ "severity": "CRITICAL",
+ }
+ with pytest.raises(RuntimeError, match="requires definition.required_boundaries as list"):
+ ContractValidator().validate_contract({}, {"state": {"capability_boundaries": []}}, bad_boundaries)
+
+ bad_capability_boundaries = {
+ "contract_id": "capability_boundary_respected",
+ "layer": "governance",
+ "type": "invariant",
+ "definition": {"rule": "required_boundaries_preserved", "required_boundaries": []},
+ "severity": "CRITICAL",
+ }
+ with pytest.raises(RuntimeError, match="requires reconstructed capability_boundaries as list"):
+ ContractValidator().validate_contract({}, {"state": {"capability_boundaries": "not-a-list"}}, bad_capability_boundaries)
+
+ bad_edges = {
+ "contract_id": "dependency_chain_preserved",
+ "layer": "relational",
+ "type": "invariant",
+ "definition": {"rule": "required_dependency_edges_preserved", "required_edges": "not-a-list"},
+ "severity": "HIGH",
+ }
+ with pytest.raises(RuntimeError, match="requires definition.required_edges as list"):
+ ContractValidator().validate_contract(
+ {},
+ {"dependency_graph": _graph_payload(["read_context", "validate_external_action"], [])},
+ bad_edges,
+ )
diff --git a/tests/test_mcp_trace_corruption_validation.py b/tests/test_mcp_trace_corruption_validation.py
index 06055f3..94413a6 100644
--- a/tests/test_mcp_trace_corruption_validation.py
+++ b/tests/test_mcp_trace_corruption_validation.py
@@ -103,28 +103,7 @@ def _terminal_action(trace_doc: dict[str, object], *, path: Path) -> str | None:
return actions[-1]
-NATIVE_CONTRACT_COVERED_CORRUPTIONS = {
- "mcp_trace_replay_degraded_v1::insert_unvalidated_action",
-}
-ADAPTER_GAP_CORRUPTIONS = {
- "mcp_trace_replay_degraded_v1::collapse_capability_boundary",
- "mcp_trace_replay_degraded_v1::drop_approval_gate",
- "mcp_trace_replay_degraded_v1::remove_dependency_edge",
- "mcp_trace_replay_degraded_v1::swap_tool_order",
- "mcp_trace_replay_degraded_v1::truncate_recovery_path",
- "mcp_trace_replay_mild_v1::collapse_capability_boundary",
- "mcp_trace_replay_mild_v1::drop_approval_gate",
- "mcp_trace_replay_mild_v1::insert_unvalidated_action",
- "mcp_trace_replay_mild_v1::remove_dependency_edge",
- "mcp_trace_replay_mild_v1::swap_tool_order",
- "mcp_trace_replay_mild_v1::truncate_recovery_path",
- "mcp_trace_replay_moderate_v1::collapse_capability_boundary",
- "mcp_trace_replay_moderate_v1::drop_approval_gate",
- "mcp_trace_replay_moderate_v1::insert_unvalidated_action",
- "mcp_trace_replay_moderate_v1::remove_dependency_edge",
- "mcp_trace_replay_moderate_v1::swap_tool_order",
- "mcp_trace_replay_moderate_v1::truncate_recovery_path",
-}
+ADAPTER_GAP_CORRUPTIONS: set[str] = set()
def _failed_labels(results: list[ValidationResult]) -> set[str]:
@@ -362,8 +341,8 @@ def test_materialized_corruptions_map_into_contract_validator_with_expected_fail
entries = _materialized_entries()
all_corruption_ids = {str(entry["corruption_id"]) for entry in entries}
- assert NATIVE_CONTRACT_COVERED_CORRUPTIONS.isdisjoint(ADAPTER_GAP_CORRUPTIONS)
- assert NATIVE_CONTRACT_COVERED_CORRUPTIONS | ADAPTER_GAP_CORRUPTIONS == all_corruption_ids
+ native_contract_covered_corruptions = all_corruption_ids - ADAPTER_GAP_CORRUPTIONS
+ assert native_contract_covered_corruptions == all_corruption_ids
for entry in entries:
corruption_id = str(entry["corruption_id"])
@@ -395,16 +374,8 @@ def test_materialized_corruptions_map_into_contract_validator_with_expected_fail
expected_label = entry["expected_failure_label"]
failed_labels = _failed_labels(results)
- if corruption_id in NATIVE_CONTRACT_COVERED_CORRUPTIONS:
- assert expected_label in failed_labels, (
- f"native-covered corruption lost expected label emission: {corruption_id}; "
- f"expected {expected_label!r}; observed {sorted(failed_labels)}"
- )
- else:
- assert corruption_id in ADAPTER_GAP_CORRUPTIONS, f"unclassified corruption_id: {corruption_id}"
- assert expected_label in FAILURE_TAXONOMY
- assert expected_label not in failed_labels, (
- f"adapter-gap corruption now emits expected label: {corruption_id}; "
- f"move this entry from ADAPTER_GAP_CORRUPTIONS to NATIVE_CONTRACT_COVERED_CORRUPTIONS; "
- f"observed labels: {sorted(failed_labels)}"
- )
+ assert corruption_id not in ADAPTER_GAP_CORRUPTIONS
+ assert expected_label in failed_labels, (
+ f"native-covered corruption missing expected label emission: {corruption_id}; "
+ f"expected {expected_label!r}; observed {sorted(failed_labels)}"
+ )
diff --git a/tests/test_tool_ordering_replay_artifact.py b/tests/test_tool_ordering_replay_artifact.py
index 92c1338..7e12abf 100644
--- a/tests/test_tool_ordering_replay_artifact.py
+++ b/tests/test_tool_ordering_replay_artifact.py
@@ -17,6 +17,7 @@
"UNAUTHORIZED_CAPABILITY_PATH",
"APPROVAL_GATE_LOSS",
"POLICY_ENFORCEMENT_GAP",
+ "DEPENDENCY_CHAIN_BREAK",
}