Contract Governance Automation: Linting, Diffing, Policy-as-Code, CI Gates, and Registry Hooks
Learn Java API Contract Engineering, Event Contract Engineering & Schema Governance - Part 026
Contract governance automation for Java platforms: lint rules, diff engines, policy-as-code, CI/CD gates, schema registry hooks, catalog sync, generated code checks, and automated risk classification.
Part 026 — Contract Governance Automation: Linting, Diffing, Policy-as-Code, CI Gates, and Registry Hooks
Tujuan Pembelajaran
Governance manual tidak scale. Jika setiap contract change harus dibaca dari nol oleh senior architect, organisasi akan lambat atau governance akan di-bypass.
Contract governance yang matang menggabungkan:
- automated validation;
- linting;
- compatibility diff;
- policy-as-code;
- generated code compile;
- schema registry gates;
- AsyncAPI/OpenAPI validation;
- Kafka contract diff;
- metadata enforcement;
- lifecycle checks;
- risk classification;
- approval routing;
- catalog synchronization;
- runtime telemetry feedback.
Tujuannya bukan menghilangkan review manusia. Tujuannya:
Automate the obvious, highlight the dangerous, and preserve human attention for semantic decisions.
Setelah part ini, kamu harus mampu:
- mendesain CI pipeline untuk contract governance;
- membuat lint rules untuk OpenAPI, AsyncAPI, JSON Schema, Avro, Protobuf;
- menjalankan compatibility diff;
- menerapkan policy-as-code;
- menghubungkan contract repository dengan schema registry;
- melakukan generated Java code compatibility checks;
- mengotomasi risk classification dan reviewer routing;
- menghindari governance automation anti-pattern seperti noisy gates dan false confidence.
1. Automation Philosophy
Good automation should:
- be fast enough for PR feedback;
- be deterministic;
- produce actionable errors;
- catch repeatable mistakes;
- enforce metadata/lifecycle;
- route high-risk changes to humans;
- preserve audit evidence;
- reduce review fatigue;
- avoid blocking harmless changes unnecessarily;
- evolve with policy.
Bad automation:
- noisy;
- slow;
- unclear;
- easy to bypass;
- catches style but misses risk;
- breaks randomly;
- requires manual interpretation;
- treats every warning as blocker.
2. Governance Automation Architecture
Each step should produce machine-readable output.
3. Contract Repository as Source of Change
Recommended repository:
contracts/
├── openapi/
├── asyncapi/
├── schemas/
│ ├── avro/
│ ├── protobuf/
│ └── json-schema/
├── kafka/
│ └── topics.yaml
├── lifecycle/
├── policies/
├── examples/
├── decisions/
└── build/
Automation reads:
- contract artifacts;
- previous released version;
- policy files;
- registry state;
- catalog metadata;
- examples;
- decision records.
Avoid contract changes only in service code if enterprise governance needs cross-team visibility.
4. CI Pipeline Overview
Baseline should be last released artifact, not arbitrary main branch if releases are separate.
5. Artifact Detection
Automation should detect changed artifacts.
Example output:
changedArtifacts:
openapi:
- customer-api/openapi.yaml
asyncapi:
- case-events/asyncapi.yaml
avro:
- schemas/avro/case/CaseApproved.avsc
protobuf:
- schemas/protobuf/customer/customer_events.proto
jsonSchema:
- schemas/json/customer/CustomerActivated.schema.json
kafka:
- kafka/topics.yaml
lifecycle:
- lifecycle/deprecations.yaml
Why?
- run targeted checks;
- classify risk;
- choose reviewers;
- avoid slow full rebuild;
- generate focused report.
6. Syntax and Reference Validation
6.1 OpenAPI
Validate:
- document parses;
- version supported;
$refresolves;- schemas valid;
- operationId unique;
- examples validate where possible.
6.2 AsyncAPI
Validate:
- document parses;
- channels/operations/messages linked;
- refs resolve;
- bindings valid for supported version;
- examples validate.
6.3 Avro
Validate:
.avscparse;- named types resolve;
- defaults match type;
- union defaults valid;
- logical types valid.
6.4 Protobuf
Validate:
.protocompiles;- imports resolve;
- field numbers unique;
- reserved range syntax valid;
- package/options valid.
6.5 JSON Schema
Validate:
$schemasupported;$idpresent;- refs resolve;
- schema itself valid under meta-schema.
7. Linting
Lint rules enforce organization style and safety.
7.1 OpenAPI Lint Rules
Examples:
openapiRules:
operationIdRequired: error
operationIdStable: warning
errorResponseRequired: error
problemJsonRequired: error
noInlineResponseSchemas: warning
requestExamplesRequired: warning
paginationModelRequiredForList: error
noEntityNames:
- Entity
- Jpa
securityRequiredForNonPublic: error
7.2 AsyncAPI Lint Rules
asyncapiRules:
messageOwnerRequired: error
channelOwnerRequired: error
messageExamplesRequired: error
kafkaKeyRequired: error
orderingGuaranteeRequired: error
dataClassificationRequired: error
eventTypePastTense: warning
noGenericEventNames:
- DataChanged
- Event
- Message
7.3 Avro Lint Rules
avroRules:
namespaceRequired: error
docRequiredForStable: warning
nullableUnionNullFirst: error
addedFieldRequiresDefault: error
decimalForMoney: error
timestampLogicalTypeRequired: warning
enumDefaultRequiredForOpen: warning
7.4 Protobuf Lint Rules
protobufRules:
packageRequired: error
javaPackageRequired: error
javaMultipleFilesRequired: warning
zeroEnumUnspecified: error
removedFieldMustBeReserved: error
noFieldNumberReuse: error
noGenericMapData: warning
7.5 JSON Schema Lint Rules
jsonSchemaRules:
schemaDialectRequired: error
idRequired: error
additionalPropertiesExplicit: error
examplesRequiredForStable: warning
noMoneyAsNumber: error
oneOfRequiresDiscriminator: warning
8. Diff Engine
Diff engine compares new artifact to baseline.
8.1 OpenAPI Diff
Detect:
- path removed;
- operation removed;
- request parameter added/removed;
- request required field added;
- response field removed;
- type changed;
- status code removed;
- error schema changed;
- security requirement changed;
- operationId changed.
8.2 AsyncAPI Diff
Detect:
- channel removed/renamed;
- message removed;
- operation action changed;
- message schema changed;
- Kafka key changed;
- binding changed;
- lifecycle changed;
- replay/retention changed.
8.3 Schema Diff
Detect format-specific change.
Avro:
- added field with/without default;
- removed field;
- type change;
- enum symbol change;
- namespace/name change;
- logical type change.
Protobuf:
- tag reuse;
- removed field not reserved;
- type change;
- enum number reuse;
- oneof change;
- service method change.
JSON Schema:
- required change;
- type change;
- constraint tightening/relaxing;
- enum change;
- additionalProperties change;
- composition change.
8.4 Kafka Diff
Detect:
- topic added/removed;
- key expression changed;
- partition count changed;
- retention changed;
- cleanup policy changed;
- DLQ changed;
- classification changed;
- producer authority changed.
9. Change Classification Engine
Diff results should classify risk.
Example output:
classification:
artifact: com.acme.case.events.CaseApproved
changes:
- path: payload.reasonCode
type: field_added
compatibility: safe
reason: optional field with default UNKNOWN
- path: kafka.key
type: key_changed
compatibility: breaking
reason: changes per-aggregate ordering contract
overall: breaking
requiredActions:
- compatibilityDecisionRecord
- architectureReview
- migrationPlan
Classification is not perfect. It should be conservative.
10. Policy-as-Code
Policy-as-code turns governance rules into executable rules.
Example policy:
policies:
stableEventRequires:
- ownerTeam
- lifecycle
- dataClassification
- compatibilityMode
- goldenExample
- asyncApiMessage
breakingChangeRequires:
- decisionRecord
- migrationGuide
- consumerImpactAnalysis
- rollbackPlan
kafkaKeyChange:
allowed: false
exceptionRequires:
- architectureReview
- topicMigrationPlan
compatibilityNone:
allowed: false
exceptionRequires:
- expiryDate
- approval
Policy engine output:
policyDecision:
allowed: false
violations:
- code: KAFKA_KEY_CHANGE_REQUIRES_CDR
message: "Kafka key changed from caseId to eventId. Add CDR and migration plan."
- code: DEPRECATED_REQUIRES_REPLACEMENT
message: "Deprecated artifact lacks replacement or reason."
11. Approval Routing
Automation should route reviewers based on risk.
Example:
reviewRouting:
low:
reviewers:
- ownerTeam
medium:
reviewers:
- ownerTeam
- contract-governance
high:
reviewers:
- ownerTeam
- contract-governance
- platform-architecture
dataClassificationChange:
reviewers:
- security-data-governance
publicApiChange:
reviewers:
- developer-platform
- partner-integration-owner
kafkaKeyChange:
reviewers:
- event-platform
- affected-consumers
Do not require architecture review for every typo. Route proportionally.
12. Generated Code Checks
12.1 OpenAPI
Generate Java client/server interface.
Checks:
- generated code compiles;
- operationId stability;
- public API diff;
- sample consumer compiles;
- SDK wrapper tests pass.
12.2 Avro
Generate SpecificRecord.
Checks:
- Java classes compile;
- namespace/package stable;
- old fixture deserializes;
- generated class public API diff if exposed.
12.3 Protobuf
Compile .proto.
Checks:
- generated Java compiles;
- descriptor breaking check;
- sample consumer compiles;
- reserved fields enforced.
12.4 Governance Rule
Generated compatibility check is required if generated artifacts are consumed outside owning service.
13. Golden Example Automation
Examples should be validated automatically.
Pipeline:
Rules:
- every stable message/operation has example;
- examples validate;
- examples use realistic fake IDs;
- examples do not contain secrets/PII;
- docs embed examples from source file;
- old examples retained for compatibility.
Example violation:
code: EXAMPLE_SCHEMA_MISMATCH
file: examples/case-approved-v1.json
message: payload.caseVersion expected integer but got string
14. Schema Registry Hooks
Registry integration points:
- pre-register validation;
- compatibility check;
- artifact metadata validation;
- access control check;
- post-register catalog sync;
- audit event emission;
- deprecation status update.
Recommended production flow:
CI registers approved schemas.
Runtime producers look up existing schemas.
Auto-registration disabled or restricted.
14.1 Registry Pre-Commit
Before merge:
check compatibility against registry baseline
14.2 Registry Publish
After merge/release:
register artifact version with metadata
14.3 Registry Drift Detection
Scheduled job:
compare registry artifacts with contract repository and catalog
Report:
- registry artifact not in repo;
- repo artifact not in registry;
- metadata mismatch;
- compatibility rule mismatch;
- lifecycle mismatch.
15. Catalog Sync
Catalog should be generated/synced from contracts.
Inputs:
- OpenAPI;
- AsyncAPI;
- schemas;
- Kafka topic metadata;
- lifecycle metadata;
- ownership;
- examples;
- consumer registry;
- runtime telemetry.
Automation:
Catalog sync checks:
- owner exists;
- lifecycle visible;
- schema links valid;
- consumers linked;
- deprecated banners visible;
- examples render.
16. Runtime Feedback Loop
Governance automation should use runtime evidence.
Runtime signals:
- deprecated endpoint traffic;
- deprecated event consumption;
- schema version usage;
- unknown event type errors;
- DLQ by event type;
- consumer lag;
- SDK version adoption;
- field usage if instrumented;
- producer schema ID usage;
- topic access logs.
Use cases:
- block retirement if traffic exists;
- notify consumers of deprecated usage;
- detect unknown consumers;
- prioritize migration;
- identify schema versions still active.
17. Automated Risk Report
Every contract PR should get a report.
Example:
# Contract Governance Report
## Overall Risk
High
## Changed Artifacts
- `schemas/avro/case/CaseApproved.avsc`
- `asyncapi/case-events.yaml`
## Detected Changes
- Added enum symbol `MANUAL_REVIEW` to `ApprovalDecision`
- Added optional field `payload.reviewedBy`
- No Kafka topic/key change
## Compatibility
- Registry: PASS
- Generated Java: PASS
- Golden samples: PASS
- Semantic risk: Dangerous enum addition
## Required Actions
- Add Compatibility Decision Record
- Add unknown enum consumer test
- Notify registered consumers:
- case-projection-service
- approval-dashboard
This helps reviewers focus.
18. Governance Severity Levels
| Severity | Meaning | Example |
|---|---|---|
| Info | no action | description changed |
| Warning | review recommended | optional field added |
| Dangerous | approval required | enum value added |
| Error | must fix or exception | schema invalid |
| Blocker | cannot merge | Protobuf tag reuse |
Do not make all warnings blockers. That creates bypass culture.
19. Developer Experience
Governance automation should be developer-friendly.
19.1 Local Commands
Provide:
./gradlew contractValidate
./gradlew contractDiff
./gradlew contractGenerate
./gradlew contractTest
or:
make contract-check
19.2 Actionable Messages
Bad:
Policy violation: rule 73.
Good:
Breaking change: response property `customer.status` was removed.
Add a migration plan and CDR, or reintroduce the field as deprecated.
19.3 Fast Feedback
Split:
- quick validation/lint;
- deeper compatibility/generation;
- full integration tests.
20. Policy Testing
Policy-as-code must be tested.
Example test cases:
tests:
- name: added optional field is safe
inputDiff: fixtures/diff/add-optional-field.yaml
expectedRisk: low
- name: kafka key change is breaking
inputDiff: fixtures/diff/kafka-key-change.yaml
expectedRisk: high
expectedViolation: KAFKA_KEY_CHANGE_REQUIRES_CDR
- name: protobuf tag reuse is blocker
inputDiff: fixtures/diff/protobuf-tag-reuse.yaml
expectedViolation: PROTOBUF_TAG_REUSE
If policy rules are untested, governance will regress.
21. Implementation Blueprint in Gradle
Conceptual task structure:
tasks.register("contractValidate") {
dependsOn("validateOpenApi")
dependsOn("validateAsyncApi")
dependsOn("validateAvro")
dependsOn("validateProtobuf")
dependsOn("validateJsonSchema")
}
tasks.register("contractDiff") {
dependsOn("diffOpenApi")
dependsOn("diffAsyncApi")
dependsOn("diffSchemas")
dependsOn("diffKafkaTopics")
}
tasks.register("contractGenerate") {
dependsOn("generateOpenApiJava")
dependsOn("generateAvroJava")
dependsOn("generateProtobufJava")
}
tasks.register("contractCheck") {
dependsOn("contractValidate")
dependsOn("contractDiff")
dependsOn("contractGenerate")
dependsOn("validateExamples")
dependsOn("policyCheck")
}
Actual plugins/tools vary. The architecture matters.
22. Implementation Blueprint in CI
Example stages:
stages:
- detect
- validate
- lint
- diff
- compatibility
- generate
- test
- policy
- report
- publish
Job output should upload:
- validation report;
- diff report;
- generated code compile result;
- compatibility result;
- risk report;
- policy decision;
- artifacts preview.
23. Automation for Deprecation
Scheduled job:
deprecationMonitor:
checks:
- deprecatedArtifactsWithTraffic
- deprecatedArtifactsPastSunset
- deprecatedArtifactsWithoutReplacement
- newConsumersUsingDeprecatedArtifacts
- migrationStatusStale
Actions:
- notify owner;
- notify consumer;
- create issue;
- block new onboarding;
- escalate if past sunset;
- update dashboard.
24. Automation for Lifecycle
Rules:
- draft cannot publish to prod registry;
- experimental requires expiry;
- stable requires compatibility mode;
- deprecated requires migration guide;
- retired cannot be produced;
- archived is read-only;
- owner missing blocks merge.
Policy violation example:
code: EXPERIMENTAL_REQUIRES_EXPIRY
artifact: com.acme.fraud.events.FraudSignalObserved
message: Experimental artifacts must define expiresAt.
25. Automation for Security/Data
Rules:
- PII fields require classification;
- restricted schemas require access policy;
- broad topic cannot add restricted field without review;
- DLQ for restricted topic must have restricted access;
- examples must not contain real-looking secrets;
- data retention class required for regulated domain.
Sensitive field detection can be heuristic:
sensitiveFieldPatterns:
- nationalId
- ssn
- passport
- cardNumber
- biometric
But human review still needed.
26. Automated Consumer Impact
Inputs:
- consumer registry;
- runtime access logs;
- schema version usage;
- topic group IDs;
- SDK download/adoption;
- API gateway logs;
- catalog subscriptions.
Impact report:
consumerImpact:
artifact: com.acme.customer.events.CustomerActivated
knownConsumers:
- onboarding-service
- crm-sync
- case-management-service
unknownConsumersDetected: 2
tier1Consumers:
- case-management-service
deprecatedUsageLast7Days: 123481
riskBand: high
This makes retirement decisions evidence-based.
27. Automated Semantic Hints
Full semantic review cannot be automated, but hints can help.
Flag when:
- description/doc changed significantly;
- enum value added;
- status field changed;
- event name contains generic words;
- field name includes
status,type,data; - timestamp field renamed;
- key changed;
- lifecycle metadata changed;
- source/authority changed;
- data classification changed.
Example:
semanticHints:
- code: STATUS_FIELD_CHANGED
message: "Field `payload.status` changed. Confirm semantic meaning remains compatible."
- code: EVENT_DESCRIPTION_CHANGED
message: "Event description changed by 68%. Review semantic compatibility."
28. Drift Detection
Scheduled drift checks:
- OpenAPI generated from runtime differs from contract;
- AsyncAPI differs from broker metadata;
- registry schema missing from repo;
- repo schema missing from registry;
- catalog lifecycle differs from registry metadata;
- Kafka topic config differs from contract;
- runtime producer emits unregistered schema;
- deprecated event still produced after retirement.
Drift report:
drift:
- type: kafka_retention_mismatch
topic: case-events
contract: P90D
runtime: P30D
severity: high
- type: registry_artifact_without_owner
artifact: com.acme.legacy.LegacyEvent
severity: medium
Drift detection turns governance into continuous control.
29. Governance Automation Anti-Patterns
29.1 Noisy Warnings
Too many irrelevant warnings cause teams to ignore all output.
29.2 Slow Required Jobs
Contract check takes 45 minutes for a one-line doc change.
29.3 Unclear Failures
Developers cannot fix.
29.4 Style Over Risk
Blocks indentation but misses breaking field removal.
29.5 Manual Override Without Audit
Bypass becomes default path.
29.6 Policy Not Versioned
Rules change unpredictably.
29.7 CI-Only, No Runtime Drift
Runtime config diverges after merge.
29.8 Registry Auto-Register Bypasses CI
Prod schemas appear without review.
29.9 No Local Tooling
Developers learn issues only in CI.
29.10 Automation Treated as Complete Governance
Semantic review still needed.
30. Governance Automation Maturity Model
| Level | Behavior |
|---|---|
| 0 | manual review only, no consistent checks |
| 1 | schema syntax validation |
| 2 | lint + compatibility checks |
| 3 | diff classification + generated code compile |
| 4 | policy-as-code + approval routing + registry gates |
| 5 | catalog sync + runtime drift detection + consumer impact automation |
| 6 | risk analytics + lifecycle automation + telemetry-driven retirement |
Aim for Level 4 minimum for serious platform. Level 5+ for enterprise-critical API/event platforms.
31. Practice Lab
Lab 1 — Design CI Pipeline
Design CI pipeline for contract repo containing:
- OpenAPI;
- AsyncAPI;
- Avro;
- Protobuf;
- JSON Schema;
- Kafka topics.
Include stages and failure conditions.
Lab 2 — Write Lint Rules
Create 10 lint rules for event contracts. Include severity.
Lab 3 — Policy-as-Code
Write policy that:
- blocks Protobuf tag reuse;
- blocks Avro added field without default;
- requires Kafka key CDR if changed;
- requires deprecation guide;
- requires owner/lifecycle/classification.
Lab 4 — Risk Report
Given diff:
Added enum value MANUAL_REVIEW.
Added optional field reviewedBy.
No key change.
Produce automated risk report.
Lab 5 — Drift Detection
Runtime Kafka topic case-events retention is 30 days, contract says 90 days. Design drift alert and remediation workflow.
Lab 6 — Developer Experience
Design local command and error message for missing additionalProperties in JSON Schema.
32. Senior Engineer Heuristics
- Automate repeatable checks; preserve human attention for semantics.
- Governance automation must be fast, actionable, and risk-based.
- Diff classification is more useful than raw diff.
- Policy-as-code needs tests.
- Generated Java compile is part of contract governance.
- Kafka key/retention changes must be diffed like schema changes.
- Registry gates should be CI-controlled for production.
- Catalog sync prevents tribal knowledge.
- Runtime drift detection closes the loop.
- Warnings must be meaningful or they become noise.
- Manual overrides need audit and expiry.
- Local developer tooling reduces CI frustration.
- Examples should be validated and reused in docs/tests.
- Security/data rules should run early, not after release.
- Automation that only validates syntax creates false confidence.
33. Summary
Contract governance automation turns review principles into repeatable engineering controls. It validates artifacts, lints style and safety rules, diffs against baselines, classifies risk, checks compatibility, compiles generated Java code, validates examples, enforces policy-as-code, routes approvals, publishes to registry, syncs catalog, and detects runtime drift.
Main takeaways:
- automate syntax, lint, diff, compatibility, generated code, examples, lifecycle, and policy;
- keep semantic decisions human but highlight risks automatically;
- make CI reports actionable;
- include Kafka operational metadata in diff/governance;
- use schema registry through controlled CI/CD workflows;
- sync registry/catalog/docs from source contracts;
- use runtime telemetry for deprecation and drift;
- test governance policies themselves;
- avoid noisy or slow gates;
- governance automation should accelerate safe change and block unsafe surprise.
Part berikutnya membahas contract diff engineering: how to design diff algorithms, classify changes, handle schema formats, detect semantic hints, calculate risk scores, and produce reviewer-friendly reports.
You just completed lesson 26 in deepen practice. Use the series map if you want to review the broader track, or continue directly into the next lesson while the context is still warm.
Keep the momentum while the lesson is still fresh. Move backward for review or continue forward into the next concept.