Commit f8d421e
feat(decisioning): framework-wide async-completion webhooks + #930 review fixes
Deliver the spec-required terminal completion / failure webhook on the
async (handoff) path of every spec-eligible verb when the buyer
registered push_notification_config (adcp#5389). Previously the SDK
emitted only on the sync path; create_media_buy / get_products /
get_signals and all other async ops left a registered push URL silent
and the buyer polling tasks/get.
Seam (approach a): emit centrally from the background completion path in
dispatch._project_handoff — the single seam every async task flows
through (_invoke_platform_method for all verbs, plus proposal finalize).
The terminal webhook fires EXACTLY ONCE after registry.complete /
registry.fail, with the buyer's operation_id echoed verbatim and the
registry task_id included. The sync auto-emit gate already skips the
{task_id, status} submitted projection, so the two paths never
double-deliver. Webhook emission lives in the decisioning runtime
(webhook_emit.emit_terminal_completion_webhook), reusing the sync path's
WebhookSender / supervisor and send_mcp payload builder; the pluggable
TaskRegistry stays webhook-agnostic. Gated by auto_emit_completion_webhooks
so manual-emit adopters are unaffected; no change to the sync defaults.
- webhook_emit.py: emit_terminal_completion_webhook (self-isolating,
logged-and-swallowed) + operation_id extraction from push config.
- dispatch.py: thread webhook_target / webhook_auto_emit through
_invoke_platform_method -> _project_handoff; fire on both the
registry.complete (completed) and _fail (failed) terminal arms.
- handler.py: _handoff_webhook_kwargs() threaded into every spec-eligible
shim (create/update_media_buy, sync_creatives, get/activate_signal,
get_products, sync_audiences/catalogs, brand/rights, property_list).
- webhook_supervisor{,_pg}.py: add operation_id to send_mcp; Pg persists
it on the queue row (CREATE column + ADD COLUMN IF NOT EXISTS backfill)
and replays it from the worker.
Review fixes on #930:
- MUST-FIX docstrings: corrected the now-true claims — async terminal
completion delivers via push webhook when configured, always via
tasks/get polling (handler / serve / specialism docstrings).
- MUST-FIX dead guard arm (c): removed the unreachable post-dispatch
assert_account_resolved_for_async call; documented that
compose_caller_identity owns the no-push-handoff + unresolved-account
case (fails closed terminally at _build_ctx before any task is minted).
Added a test asserting no registry row is issued.
- SHOULD-FIX side-effect leak (b): reject_wholesale_handoff_before_launch
wired as a pre_handoff_reject callback so a wholesale handoff is
rejected BEFORE the registry row / background task / draft / webhook --
no side effects for a buyer told 'rejected'. Test asserts an empty
registry after rejection.
- SHOULD-FIX persist-draft: regression test pinning that fields= /
pagination= projections shape only the wire response, never the
persisted draft (full product pricing retained).
- SHOULD-FIX wire-validator: tightened the discovery submitted test to
assert variant == 'submitted' (no skip escape hatch).
- Added async-completion webhook tests on get_products, get_signals,
create_media_buy (one completed webhook; operation_id echoed, task_id,
result in payload), the failure path (one failed webhook), and the
no-push no-webhook case. Updated the create_media_buy handoff test to
assert the conformant exactly-once behavior.
No ADCP_VERSION bump, no schema re-download, no public-API export change.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>1 parent a603199 commit f8d421e
13 files changed
Lines changed: 1015 additions & 73 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
114 | 114 | | |
115 | 115 | | |
116 | 116 | | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
117 | 155 | | |
118 | | - | |
| 156 | + | |
| 157 | + | |
119 | 158 | | |
| 159 | + | |
120 | 160 | | |
121 | | - | |
| 161 | + | |
| 162 | + | |
122 | 163 | | |
123 | 164 | | |
124 | 165 | | |
125 | 166 | | |
126 | 167 | | |
127 | 168 | | |
128 | 169 | | |
129 | | - | |
130 | | - | |
131 | | - | |
132 | | - | |
133 | | - | |
134 | | - | |
135 | | - | |
136 | | - | |
137 | | - | |
138 | | - | |
139 | | - | |
140 | | - | |
| 170 | + | |
141 | 171 | | |
142 | 172 | | |
143 | 173 | | |
| |||
156 | 186 | | |
157 | 187 | | |
158 | 188 | | |
159 | | - | |
160 | | - | |
161 | | - | |
162 | | - | |
163 | | - | |
164 | | - | |
165 | | - | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
166 | 204 | | |
167 | 205 | | |
168 | 206 | | |
| |||
245 | 283 | | |
246 | 284 | | |
247 | 285 | | |
| 286 | + | |
248 | 287 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
66 | 66 | | |
67 | 67 | | |
68 | 68 | | |
| 69 | + | |
69 | 70 | | |
70 | 71 | | |
71 | 72 | | |
| |||
77 | 78 | | |
78 | 79 | | |
79 | 80 | | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
80 | 85 | | |
81 | 86 | | |
82 | 87 | | |
| |||
1305 | 1310 | | |
1306 | 1311 | | |
1307 | 1312 | | |
| 1313 | + | |
| 1314 | + | |
| 1315 | + | |
1308 | 1316 | | |
1309 | 1317 | | |
1310 | 1318 | | |
| |||
1351 | 1359 | | |
1352 | 1360 | | |
1353 | 1361 | | |
| 1362 | + | |
| 1363 | + | |
| 1364 | + | |
| 1365 | + | |
| 1366 | + | |
| 1367 | + | |
| 1368 | + | |
| 1369 | + | |
| 1370 | + | |
| 1371 | + | |
| 1372 | + | |
| 1373 | + | |
| 1374 | + | |
| 1375 | + | |
| 1376 | + | |
| 1377 | + | |
| 1378 | + | |
| 1379 | + | |
| 1380 | + | |
| 1381 | + | |
| 1382 | + | |
| 1383 | + | |
| 1384 | + | |
| 1385 | + | |
1354 | 1386 | | |
1355 | 1387 | | |
1356 | 1388 | | |
| |||
1513 | 1545 | | |
1514 | 1546 | | |
1515 | 1547 | | |
| 1548 | + | |
| 1549 | + | |
| 1550 | + | |
| 1551 | + | |
| 1552 | + | |
| 1553 | + | |
| 1554 | + | |
1516 | 1555 | | |
1517 | 1556 | | |
1518 | 1557 | | |
| |||
1522 | 1561 | | |
1523 | 1562 | | |
1524 | 1563 | | |
| 1564 | + | |
| 1565 | + | |
1525 | 1566 | | |
1526 | 1567 | | |
1527 | 1568 | | |
| |||
1588 | 1629 | | |
1589 | 1630 | | |
1590 | 1631 | | |
| 1632 | + | |
| 1633 | + | |
1591 | 1634 | | |
1592 | 1635 | | |
1593 | 1636 | | |
| |||
1647 | 1690 | | |
1648 | 1691 | | |
1649 | 1692 | | |
1650 | | - | |
| 1693 | + | |
| 1694 | + | |
| 1695 | + | |
| 1696 | + | |
| 1697 | + | |
| 1698 | + | |
| 1699 | + | |
| 1700 | + | |
| 1701 | + | |
| 1702 | + | |
| 1703 | + | |
| 1704 | + | |
| 1705 | + | |
| 1706 | + | |
| 1707 | + | |
| 1708 | + | |
| 1709 | + | |
| 1710 | + | |
| 1711 | + | |
| 1712 | + | |
1651 | 1713 | | |
1652 | 1714 | | |
1653 | 1715 | | |
| |||
1699 | 1761 | | |
1700 | 1762 | | |
1701 | 1763 | | |
1702 | | - | |
| 1764 | + | |
| 1765 | + | |
| 1766 | + | |
| 1767 | + | |
| 1768 | + | |
| 1769 | + | |
| 1770 | + | |
| 1771 | + | |
| 1772 | + | |
| 1773 | + | |
| 1774 | + | |
| 1775 | + | |
| 1776 | + | |
| 1777 | + | |
| 1778 | + | |
| 1779 | + | |
| 1780 | + | |
1703 | 1781 | | |
1704 | 1782 | | |
1705 | 1783 | | |
| |||
1792 | 1870 | | |
1793 | 1871 | | |
1794 | 1872 | | |
| 1873 | + | |
| 1874 | + | |
| 1875 | + | |
| 1876 | + | |
| 1877 | + | |
| 1878 | + | |
| 1879 | + | |
| 1880 | + | |
| 1881 | + | |
| 1882 | + | |
| 1883 | + | |
| 1884 | + | |
| 1885 | + | |
| 1886 | + | |
| 1887 | + | |
| 1888 | + | |
1795 | 1889 | | |
1796 | 1890 | | |
1797 | 1891 | | |
| |||
0 commit comments