# Replay Manifest v2 Acceptance Contract _Last updated: 2025-12-13. Owner: BE-Base Platform Guild._ This document defines the acceptance criteria and test vectors for replay manifest v2, enabling Task 19 (GAP-REP-004) to proceed with implementation. --- ## 1. Overview Replay manifest v2 introduces: - **BLAKE3 graph hashes:** Primary hash algorithm for reachability graphs - **Sorted CAS entries:** Deterministic ordering of all CAS references - **hashAlg fields:** Explicit algorithm declarations for forward compatibility - **code_id coverage:** Coverage metrics for stripped binary handling --- ## 2. Schema Changes (v1 → v2) ### 2.1 Version Field ```json { "schemaVersion": "2.0", ... } ``` ### 2.2 Hash Algorithm Declaration All hash fields now include explicit algorithm: ```json { "reachability": { "graphs": [ { "hash": "blake3:a1b2c3d4e5f6...", "hashAlg": "blake3-256", "casUri": "cas://reachability/graphs/blake3:a1b2c3d4..." } ], "runtimeTraces": [ { "hash": "sha256:feedface...", "hashAlg": "sha256", "casUri": "cas://reachability/runtime/sha256:feedface..." } ] } } ``` ### 2.3 Sorted CAS Entries All arrays must be sorted by deterministic key: | Array | Sort Key | |-------|----------| | `reachability.graphs[]` | `casUri` (lexicographic) | | `reachability.runtimeTraces[]` | `casUri` (lexicographic) | | `inputs.feeds[]` | `name` (lexicographic) | | `inputs.tools[]` | `name` (lexicographic) | ### 2.4 Code ID Coverage New field for stripped binary support: ```json { "reachability": { "code_id_coverage": { "total_nodes": 1247, "nodes_with_symbol_id": 1189, "nodes_with_code_id": 58, "coverage_percent": 100.0 } } } ``` --- ## 3. CAS Registration Gates ### 3.1 Required Registration All referenced artifacts must be registered in CAS before manifest finalization: | Artifact Type | CAS Path Pattern | Required | |---------------|------------------|----------| | Graph body | `cas://reachability/graphs/{hash}` | Yes | | Graph DSSE | `cas://reachability/graphs/{hash}.dsse` | Yes | | Runtime trace | `cas://reachability/runtime/{hash}` | Conditional | | Edge bundle | `cas://reachability/edges/{graph_hash}/{bundle_id}` | Conditional | ### 3.2 Registration Validation Before signing a replay manifest: 1. Verify all `casUri` references resolve to existing CAS objects 2. Verify hash matches CAS content 3. Verify DSSE envelope exists for all graph references 4. Fail manifest creation if any reference is missing ### 3.3 Validation API ```csharp public interface ICasValidator { Task ValidateAsync(string casUri, string expectedHash); Task ValidateBatchAsync(IEnumerable refs); } public record CasValidationResult( bool IsValid, string? ActualHash, string? Error ); ``` --- ## 4. Acceptance Test Vectors ### 4.1 Minimal Valid Manifest v2 ```json { "schemaVersion": "2.0", "scan": { "id": "scan-test-001", "time": "2025-12-13T10:00:00Z", "mode": "record", "scannerVersion": "10.2.0" }, "subject": { "ociDigest": "sha256:abc123..." }, "inputs": { "feeds": [], "tools": [] }, "reachability": { "graphs": [ { "kind": "static", "analyzer": "scanner.java@10.2.0", "hash": "blake3:a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2", "hashAlg": "blake3-256", "casUri": "cas://reachability/graphs/blake3:a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2" } ], "runtimeTraces": [], "code_id_coverage": { "total_nodes": 100, "nodes_with_symbol_id": 100, "nodes_with_code_id": 0, "coverage_percent": 100.0 } }, "outputs": {}, "provenance": {} } ``` **Expected canonical hash:** `sha256:e7f8a9b0...` (computed from canonical JSON) ### 4.2 Manifest with Runtime Traces ```json { "schemaVersion": "2.0", "scan": { "id": "scan-test-002", "time": "2025-12-13T11:00:00Z", "mode": "record", "scannerVersion": "10.2.0" }, "reachability": { "graphs": [ { "kind": "static", "analyzer": "scanner.java@10.2.0", "hash": "blake3:1111111111111111111111111111111111111111111111111111111111111111", "hashAlg": "blake3-256", "casUri": "cas://reachability/graphs/blake3:1111111111111111111111111111111111111111111111111111111111111111" } ], "runtimeTraces": [ { "source": "eventpipe", "hash": "sha256:2222222222222222222222222222222222222222222222222222222222222222", "hashAlg": "sha256", "casUri": "cas://reachability/runtime/sha256:2222222222222222222222222222222222222222222222222222222222222222", "recordedAt": "2025-12-13T10:30:00Z" } ] } } ``` ### 4.3 Sorting Validation Vector Input (unsorted): ```json { "reachability": { "graphs": [ {"casUri": "cas://reachability/graphs/blake3:zzzz...", "kind": "framework"}, {"casUri": "cas://reachability/graphs/blake3:aaaa...", "kind": "static"} ] } } ``` Expected output (sorted): ```json { "reachability": { "graphs": [ {"casUri": "cas://reachability/graphs/blake3:aaaa...", "kind": "static"}, {"casUri": "cas://reachability/graphs/blake3:zzzz...", "kind": "framework"} ] } } ``` ### 4.4 Invalid Manifest Vectors | Test Case | Input | Expected Error | |-----------|-------|----------------| | Missing schemaVersion | `{}` | `REPLAY_MANIFEST_MISSING_VERSION` | | Invalid version | `{"schemaVersion": "1.0"}` | `REPLAY_MANIFEST_VERSION_MISMATCH` (when v2 required) | | Missing hashAlg | `{"hash": "blake3:..."}` | `REPLAY_MANIFEST_MISSING_HASH_ALG` | | Unsorted graphs | See 4.3 input | `REPLAY_MANIFEST_UNSORTED_ENTRIES` | | Missing CAS reference | `{"casUri": "cas://missing/..."}` | `REPLAY_MANIFEST_CAS_NOT_FOUND` | | Hash mismatch | CAS content differs | `REPLAY_MANIFEST_HASH_MISMATCH` | --- ## 5. Migration Path ### 5.1 v1 → v2 Upgrade ```csharp public static ReplayManifest UpgradeToV2(ReplayManifest v1) { return v1 with { SchemaVersion = "2.0", Reachability = v1.Reachability with { Graphs = v1.Reachability.Graphs .Select(g => g with { HashAlg = InferHashAlg(g.Hash) }) .OrderBy(g => g.CasUri) .ToList(), RuntimeTraces = v1.Reachability.RuntimeTraces .Select(t => t with { HashAlg = InferHashAlg(t.Hash) }) .OrderBy(t => t.CasUri) .ToList() } }; } ``` ### 5.2 Backward Compatibility - v2 readers MUST accept v1 manifests with warning - v2 writers MUST always emit v2 format - v1 writers deprecated after 2026-03-01 --- ## 6. Test Fixture Locations ``` tests/Replay/ fixtures/ manifest-v2-minimal.json manifest-v2-with-runtime.json manifest-v2-sorted.json manifest-v2-code-id-coverage.json invalid/ manifest-missing-version.json manifest-unsorted.json manifest-missing-hashalg.json golden/ manifest-v2-canonical.golden.json manifest-v2-hash.golden.txt ``` --- ## 7. Implementation Checklist - [ ] Update `ReplayManifest` record with v2 fields - [ ] Add `hashAlg` to all hash-bearing types - [ ] Implement sorting in `ReachabilityReplayWriter` - [ ] Add CAS registration validation - [ ] Create test fixtures - [ ] Update `DETERMINISTIC_REPLAY.md` section 3 - [ ] Wire into RecordModeService --- _Last updated: 2025-12-13. See Sprint 0401 GAP-REP-004 for implementation._