Evidence Integration Adapter Specification

Version: 1.0.0
Status: Draft
Date: 2025-12-31
Context: shared/adapters
Satisfies: PRD-021, SDS-047, ADR-011


Purpose

This specification defines the adapter layer for integrating Giskard AI testing evidence with the GovernedSpeed™ Governance Runtime (SDS-047) and anchoring evidence hashes to the Internal Federated Ledger (IFL per ADR-011).


Architecture

sequenceDiagram
    participant Giskard
    participant EvidenceAdapter
    participant SDS047 as SDS-047 Evidence Service
    participant IFL as Internal Federated Ledger
    participant OTLP as OpenTelemetry Collector

    Giskard->>EvidenceAdapter: submit_test_results(fairness_report)
    EvidenceAdapter->>EvidenceAdapter: compute_sha256(content)
    EvidenceAdapter->>SDS047: SubmitEvidence(artifactType, content, hash)
    SDS047->>SDS047: validate_hash(content, hash)
    SDS047->>IFL: anchor_hash(artifactId, hash)
    IFL-->>SDS047: anchor_receipt
    SDS047->>OTLP: emit_metric(evidence.submitted)
    SDS047-->>EvidenceAdapter: EvidenceSubmitted(artifactId, hash)
    EvidenceAdapter-->>Giskard: submission_receipt

Components

1. GiskardEvidenceAdapter

Responsibility: Transforms Giskard test outputs into SDS-047 evidence artifacts

Interface:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class GiskardEvidenceAdapter:
    def submit_fairness_report(
        self,
        model_version: str,
        test_suite: GiskardTestSuite,
        results: GiskardTestResults
    ) -> EvidenceReceipt:
        """
        Submits Giskard fairness test results as evidence.
        
        Args:
            model_version: Model version being tested
            test_suite: Giskard test suite configuration
            results: Test execution results
            
        Returns:
            EvidenceReceipt with artifact ID and hash
            
        Raises:
            HashValidationError: If computed hash doesn't match
            SubmissionError: If SDS-047 submission fails
        """
        pass
    
    def submit_safety_report(
        self,
        model_version: str,
        adversarial_tests: GiskardAdversarialResults
    ) -> EvidenceReceipt:
        """Submits adversarial/safety test results as evidence."""
        pass

Mapping:

Giskard Output Evidence Artifact Type Required Fields
fairness_report.json fairness_report protected_attributes, subgroup_delta, disparate_impact_ratio
adversarial_report.json safety_report attack_types, success_rate, mitigation
data_quality_report.json evaluation completeness_score, accuracy_score, known_issues

2. IFLAnchorAdapter

Responsibility: Anchors evidence hashes to Internal Federated Ledger for immutability

Interface:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class IFLAnchorAdapter:
    def anchor_evidence_hash(
        self,
        artifact_id: str,
        evidence_hash: str,
        timestamp: datetime
    ) -> AnchorReceipt:
        """
        Anchors evidence hash to IFL.
        
        Args:
            artifact_id: UUID of evidence artifact
            evidence_hash: SHA256 hash (64 hex chars)
            timestamp: Submission timestamp
            
        Returns:
            AnchorReceipt with ledger transaction ID and merkle proof
            
        Raises:
            LedgerUnavailableError: If IFL is unreachable
            InvalidHashError: If hash format is invalid
        """
        pass
    
    def verify_anchor(
        self,
        artifact_id: str,
        evidence_hash: str
    ) -> AnchorVerification:
        """Verifies evidence hash exists in IFL and hasn't been tampered."""
        pass

IFL Integration:

Per ADR-011, the IFL provides:


3. EvidenceSubmissionWorkflow

End-to-End Flow:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 1. Giskard executes tests
test_suite = GiskardTestSuite.from_yaml("fairness_tests.yaml")
results = test_suite.run(model)

# 2. Adapter transforms results
adapter = GiskardEvidenceAdapter(
    sds047_client=Evidence ServiceClient("http://localhost:8080"),
    ifl_client=IFLClient("http://localhost:5000")
)

# 3. Submit to SDS-047 with automatic hashing
receipt = adapter.submit_fairness_report(
    model_version="customer-churn-v2.1.0",
    test_suite=test_suite,
    results=results
)

# Output:
# EvidenceReceipt(
#     artifact_id="01932e5f-8c7a-7b6c-9d8e-0f1a2b3c4d5e",
#     evidence_hash="a3f5d8c2e7b4f9a1c6d8e2f5a3b7c9d1e4f8a2b5c7d9e1f3a5b8c2d4e6f9a1c3",
#     ifl_anchor_id="tx-2025123123456789",
#     submitted_at="2025-12-31T12:34:56Z"
# )

Data Schemas

EvidenceReceipt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "EvidenceReceipt",
  "type": "object",
  "required": ["artifact_id", "evidence_hash", "ifl_anchor_id", "submitted_at"],
  "properties": {
    "artifact_id": {
      "type": "string",
      "format": "uuid",
      "description": "UUID v7 of evidence artifact"
    },
    "evidence_hash": {
      "type": "string",
      "pattern": "^[a-f0-9]{64}$",
      "description": "SHA256 hash of artifact content"
    },
    "ifl_anchor_id": {
      "type": "string",
      "description": "IFL transaction ID for ledger anchor"
    },
    "submitted_at": {
      "type": "string",
      "format": "date-time"
    }
  }
}

GiskardFairnessReport (Input)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
  "model_version": "customer-churn-v2.1.0",
  "test_suite_id": "fairness-suite-v1",
  "protected_attributes": ["gender", "race", "age"],
  "subgroup_delta": 0.03,
  "disparate_impact_ratio": 0.15,
  "test_results": [
    {
      "test_name": "demographic_parity",
      "passed": true,
      "threshold": 0.05,
      "actual": 0.03
    }
  ],
  "executed_at": "2025-12-31T12:00:00Z"
}

Error Handling

Error Cause Recovery
HashValidationError Computed hash ≠ SDS-047 hash Recompute and retry
SubmissionError SDS-047 service unavailable Retry with exponential backoff
LedgerUnavailableError IFL unreachable Queue for retry; proceed without anchor (logged)
InvalidHashError Hash format incorrect Fix input data; don’t submit

Idempotency:

Per SDS-047 SubmitEvidence command:


Configuration

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# config/evidence-integration.yaml
giskard:
  api_url: "http://localhost:9000"
  timeout_seconds: 30

sds047:
  evidence_service_url: "http://localhost:8080"
  retry_attempts: 3
  retry_backoff_ms: [1000, 2000, 4000]

ifl:
  ledger_url: "http://localhost:5000"
  enable_anchoring: true  # Set to false to disable IFL anchoring
  anchor_timeout_seconds: 10

observability:
  export_metrics: true
  otlp_endpoint: "http://localhost:4317"

Testing Strategy

Unit Tests

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def test_giskard_adapter_fairness_report_submission():
    # Mock Giskard results
    results = GiskardTestResults(
        protected_attributes=["gender"],
        subgroup_delta=0.03
    )
    
    # Mock SDS-047 client
    sds047_mock = Mock(spec=EvidenceServiceClient)
    sds047_mock.submit_evidence.return_value = EvidenceReceipt(...)
    
    # Test adapter
    adapter = GiskardEvidenceAdapter(sds047_client=sds047_mock)
    receipt = adapter.submit_fairness_report("v1.0", test_suite, results)
    
    # Assertions
    assert receipt.artifact_id is not None
    assert len(receipt.evidence_hash) == 64
    sds047_mock.submit_evidence.assert_called_once()

Integration Tests

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def test_end_to_end_evidence_submission_with_ifl():
    # Use Testcontainers for SDS-047 + IFL
    with EvidenceServiceContainer() as sds047, IFLContainer() as ifl:
        adapter = GiskardEvidenceAdapter(
            sds047_client=EvidenceServiceClient(sds047.get_url()),
            ifl_client=IFLClient(ifl.get_url())
        )
        
        # Submit real evidence
        receipt = adapter.submit_fairness_report(...)
        
        # Verify IFL anchor
        verification = adapter.ifl_client.verify_anchor(
            receipt.artifact_id,
            receipt.evidence_hash
        )
        assert verification.is_valid

Deployment

Python Package

1
pip install sea-evidence-adapters

Usage in Model Training Pipeline

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from sea_evidence_adapters import GiskardEvidenceAdapter

# After model evaluation
adapter = GiskardEvidenceAdapter.from_config("evidence-integration.yaml")

# Submit fairness evidence
fairness_receipt = adapter.submit_fairness_report(
    model_version=model.version,
    test_suite=fairness_suite,
    results=fairness_results
)

# Submit safety evidence
safety_receipt = adapter.submit_safety_report(
    model_version=model.version,
    adversarial_tests=safety_results
)

# Check compliance
if not fairness_receipt.artifact_id:
    raise ComplianceError("Fairness evidence submission failed")


Revision History

Version Date Changes
1.0.0 2025-12-31 Initial specification

References