SDS-019: Event Contract Governance

Type

Software Design Specification - Governance Protocol

Status

Draft

Purpose

Defines the Event Evolution Governance model for SEA-Forge™. This specification transforms event schemas from aspirational documentation into enforceable contracts with strict forward/backward compatibility rules. It establishes the Schema Registry structure, Consumer Contract format, and the Regime Attribution logic for translation loss.

1. Governance Model

1.1. The Contract

Every event emitted in the system must be governed by a Producer Schema. Every consumer must declare its expectations via a Consumer Contract. The CI/CD pipeline enforces compatibility between Producers and Consumers before deployment.

1.2. Regime Attribution

Events are explicit projections of an Invariant Regime (see REF-012).


2. Schema Registry (Producer Side)

2.1. Registry Location

The source of truth for all event schemas is the SEA™ Monorepo: docs/schemas/events/<domain>/<event-type>/<version>.json

Example Path: docs/schemas/events/semantic-core/sea.policy.eval/v1.json

2.2. Producer Schema Example

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": "PolicyEvaluationEvent",
  "description": "Emitted when a SEA™ DSL policy is evaluated.",
  "type": "object",
  "properties": {
    "specs": {
      "regimeId": { "type": "string", "description": "The Invariant Regime governing this evaluation." },
      "schemaId": { "type": "string", "const": "sea.policy.eval.v1" }
    },
    "payload": {
      "type": "object",
      "properties": {
        "policyId": { "type": "string" },
        "result": { "type": "string", "enum": ["compliant", "non-compliant", "unknown"] },
        "translationLoss": {
          "type": "array",
          "items": { "type": "string" },
          "description": "List of semantic nuances lost in this projection."
        }
      },
      "required": ["policyId", "result"]
    }
  },
  "required": ["specs", "payload"]
}

3. Consumer Contracts

Consumers must declare what fields they rely on. This allows the system to determine if a Producer change (e.g., removing a field) actually breaks any active consumers.

3.1. Contract Declaration Format

Located in: apps/<consumer-app>/contracts/<event-type>.contract.yaml

Example Contract:

1
2
3
4
5
6
7
8
9
10
consumer: "governance-dashboard"
event: "sea.policy.eval.v1"
expectations:
  - field: "payload.result"
    assertion: "must be one of [compliant, non-compliant, unknown]"
  - field: "specs.regimeId"
    assertion: "present"
  # Note: Consumer explicitly does NOT rely on 'translationLoss', so removing it is safe for this consumer.
compatibility:
  mode: "forward" # Consumer must handle new fields gracefully

4. Schema Change Governance

Producer schema changes are semantic changes that affect API contracts and require formal governance.

4.1. Proposal Requirement

All producer schema changes MUST follow the SemanticChangeProposal workflow per SDS-031: Semantic Change Workflow:

Change Type changeType Value Required Approver Typical Options
Add optional field policy_update R-DS Usually single option (additive)
Add required field (new version) policy_update R-DS + R-AG Conservative (optional), Balanced (required in v2)
Remove field policy_update R-AG Conservative (deprecate), Balanced (remove in v2), Aggressive (immediate)
Change field type policy_update R-AG Always requires migration path in proposal
Major version bump policy_update R-AG Requires all 3 options with consumer impact analysis

4.2. Consumer Impact in Proposal

The SemanticChangeProposal.impactAnalysis for schema changes MUST include:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
  "impactAnalysis": {
    "projectionsAffected": [
      {
        "projectionTarget": "consumer:governance-dashboard",
        "contractPath": "apps/governance-dashboard/contracts/policy-eval.contract.yaml",
        "breakingForConsumer": true,
        "regenerationRequired": true
      }
    ],
    "compatibility": {
      "backward": false,
      "forward": true,
      "migrationPath": "Consumers upgrade to v2 schema within 30 days"
    },
    "blastRadius": {
      "consumersAffected": 3
    }
  }
}

5. Compatibility Algorithm

The Schema Evolution Guard runs in CI to check changes to Producer Schemas against registered Consumer Contracts.

4.1. Rules

  1. Backward Compatibility (Producer Constraint):
  2. Forward Compatibility (Consumer Constraint):

4.2. CI Check Pseudocode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def check_compatibility(producer_schema, consumer_contracts):
    for contract in consumer_contracts:
        if contract.event != producer_schema.schemaId:
            continue
            
        for expectation in contract.expectations:
            field_path = expectation.field
            
            # Check 1: Existence
            if not schema_has_field(producer_schema, field_path):
                return Result.BLOCK(f"Breaking Change: Field '{field_path}' removed but required by {contract.consumer}")
                
            # Check 2: Type Safety
            schema_type = get_schema_type(producer_schema, field_path)
            # Logic to verify type compatibility...
            
            # Check 3: Enum Coverage
            if expectation.assertion.startswith("must be one of"):
                required_values = parse_enum_values(expectation.assertion)
                schema_values = get_schema_enum(producer_schema, field_path)
                if not set(required_values).issubset(set(schema_values)):
                     return Result.WARN(f"Consumer {contract.consumer} handles specific enums that might have changed.")

    return Result.PASS

5. Translation Loss Representation

When projecting complex semantic states (like “Unknown due to missing data”) into simpler systems (like a boolean “is_valid”), the loss must be logged.

5.1. Explicit Field

Use a translationLoss array in the payload or metadata key.

Example:

5.2. Ledger Entry

If the loss is critical (risk of semantic failure), a Semantic Debt Item must be created (see SDS-016) referencing the event ID.


6. CI/CD Behavior

Scenario Check Result Action
Producer removes unused field PASS Allow merge.
Producer adds optional field PASS Allow merge.
Producer removes field used by Consumer BLOCK Blocking Error. Producer must restore field or Consumer must be updated first.
Producer changes enum (adds value) WARN Warning to Consumers to check exhaustiveness.
Breaking Schema Change (v1 -> v2) MANUAL Requires Major Version bump and new Schema file.