diff --git a/artifacts/evidence_index.json b/artifacts/evidence_index.json index f6f55b2..2ad2d0d 100644 --- a/artifacts/evidence_index.json +++ b/artifacts/evidence_index.json @@ -64,6 +64,29 @@ "evidence_bearing": true, "visualization_only": false }, + { + "path": "artifacts/mcp_trace_corruption_manifest.json", + "format": "json", + "generator": "scripts/generate_mcp_trace_corruptions.py", + "evidence_category": "corruption_manifest", + "evidence_role": "deterministic MCP trace corruption manifest evidence", + "fixture_families": [ + "mcp_trace_replay" + ], + "top_level_keys": [ + "allowed_operators", + "corruptions", + "manifest_id", + "summary", + "version" + ], + "deterministic_evaluation": true, + "llm_judges": "none", + "external_apis": "none", + "manifest_aligned": false, + "evidence_bearing": true, + "visualization_only": false + }, { "path": "artifacts/mcp_trace_replay_results.json", "format": "json", @@ -188,13 +211,13 @@ } ], "global_summary": { - "artifact_count": 7, - "json_artifact_count": 6, + "artifact_count": 8, + "json_artifact_count": 7, "svg_artifact_count": 1, - "evidence_bearing_count": 6, + "evidence_bearing_count": 7, "visualization_only_count": 1, - "deterministic_artifact_count": 7, - "llm_free_artifact_count": 7, - "external_api_free_artifact_count": 7 + "deterministic_artifact_count": 8, + "llm_free_artifact_count": 8, + "external_api_free_artifact_count": 8 } } diff --git a/scripts/generate_evidence_index.py b/scripts/generate_evidence_index.py index 3f14d14..8f758b9 100644 --- a/scripts/generate_evidence_index.py +++ b/scripts/generate_evidence_index.py @@ -3,6 +3,7 @@ from __future__ import annotations import json +import re from pathlib import Path from typing import Any @@ -29,6 +30,15 @@ "evidence_bearing": True, "visualization_only": False, }, + { + "path": "artifacts/mcp_trace_corruption_manifest.json", + "format": "json", + "generator": "scripts/generate_mcp_trace_corruptions.py", + "evidence_category": "corruption_manifest", + "evidence_role": "deterministic MCP trace corruption manifest evidence", + "evidence_bearing": True, + "visualization_only": False, + }, { "path": "artifacts/mcp_trace_replay_results.json", "format": "json", @@ -85,6 +95,11 @@ def _manifest_families() -> set[str]: manifest = _load_json(MANIFEST_PATH) return {str(fixture["family"]) for fixture in manifest["fixtures"]} +def _family_from_fixture_slug(slug: str) -> str | None: + match = re.match(r"^(?P.+)_[^_]+_v\d+$", slug) + if not match: + return None + return match.group("family") def _extract_fixture_families(payload: dict[str, Any]) -> list[str]: families: set[str] = set() @@ -94,6 +109,18 @@ def _extract_fixture_families(payload: dict[str, Any]) -> list[str]: families.add(family["family"]) if isinstance(payload.get("family"), str): families.add(payload["family"]) + + if isinstance(payload.get("corruptions"), list): + for corruption in payload["corruptions"]: + if not isinstance(corruption, dict): + continue + source_fixture = corruption.get("source_fixture") + if not isinstance(source_fixture, str): + continue + fixture_slug = source_fixture.rsplit("/", 1)[-1] + family = _family_from_fixture_slug(fixture_slug) + if family: + families.add(family) return sorted(families)