Context
BlueFlow's outbound Viper webhook payload exists only as a Python dataclass (ViperWebhookResponse.to_dict() in blueflow/models/viper.py). It is not part of the served OpenAPI at /api/schema/ because it is produced by a Celery task, not a DRF view.
The contract-verification approach (design session on the spike, parent EPIC's Pillar D) verifies this payload at the instance level — a representative payload emitted by test_tapirxl_viper_regression.py is validated against Viper's published integrationUpload JSON Schema. That catches real breaks but only for fields a sample happens to exercise.
This issue is the type-level upgrade: express the outbound payload as a generated schema so it can be diffed structurally (every field BlueFlow could emit), not just validated per-instance.
Why this is an upgrade, not a prerequisite
The CI-only verification works without this. This buys type-level coverage and removes reliance on sample completeness.
Seed acceptance criteria
Notes
Context
BlueFlow's outbound Viper webhook payload exists only as a Python dataclass (
ViperWebhookResponse.to_dict()inblueflow/models/viper.py). It is not part of the served OpenAPI at/api/schema/because it is produced by a Celery task, not a DRF view.The contract-verification approach (design session on the spike, parent EPIC's Pillar D) verifies this payload at the instance level — a representative payload emitted by
test_tapirxl_viper_regression.pyis validated against Viper's publishedintegrationUploadJSON Schema. That catches real breaks but only for fields a sample happens to exercise.This issue is the type-level upgrade: express the outbound payload as a generated schema so it can be diffed structurally (every field BlueFlow could emit), not just validated per-instance.
Why this is an upgrade, not a prerequisite
The CI-only verification works without this. This buys type-level coverage and removes reliance on sample completeness.
Seed acceptance criteria
@extend_schema) rather than hand-coded into_dict()integrationUploadschema in CINotes