feat: let adopters put a vendor-namespaced ext on task envelopes and reads - #2861
feat: let adopters put a vendor-namespaced ext on task envelopes and reads#2861LukasGoTom wants to merge 1 commit into
Conversation
…reads
The spec's submitted branch declares `ext`, and the task-status responses are
open objects, but the framework hard-codes the submitted envelope as
{ status, task_id } and projects only spec fields on task reads. A seller that
already knows a vendor-side identity when it hands off (an order number, a
campaign page) therefore had nowhere compliant to surface it while the task
runs — `result` is terminal-only by spec.
- `TaskHandoffOptions.ext`: echoed verbatim on the submitted envelope by
dispatchHitl (both settlement modes).
- `TaskRecord.ext`: projected as `ext` by get_task_status, tasks_get and
list_tasks items. The built-in registries never persist it; a decorating
registry attaches it at read time.
Keys are expected to sit under a vendor namespace (`ext.acme`), never a spec
field such as `media_buy_id`, which stays on the terminal artifact.
IPR Policy Agreement Required@LukasGoTom — thanks for the contribution. Before this PR can be merged, the AgenticAdvertising.Org IPR Policy requires your agreement. To agree, post a new comment on this PR with the exact phrase: Your signature is recorded once and covers all contributions to AAO repositories. See |
| * never a spec field such as `media_buy_id` — those belong on the terminal | ||
| * artifact. Not persisted; a registry decorator may re-attach it on reads. | ||
| */ | ||
| ext?: Record<string, unknown>; |
There was a problem hiding this comment.
MUST FIX: No changeset in this PR. It touches src/lib/** (non-generated) and adds new public API surface — TaskHandoffOptions.ext here, TaskRecord.ext in task-registry.ts, plus new ext projection on get_task_status/tasks_get/list_tasks. Per the repo's changeset-vs-wire-impact rule, a missing .changeset/*.md on a src/lib/** change is a blocking finding, and without it the feature never ships to npm. Additive new optional fields → minor. Run npm run changeset.
There was a problem hiding this comment.
Ladon verdict: Request changes
Request changes — 1 blocking finding.
Blocking findings
.changeset/*.md(missing) — New public API added undersrc/lib/**(TaskHandoffOptions.ext,TaskRecord.ext) without a changeset. Per the mandatory changeset-vs-wire-impact rule, a missing.changeset/*.mdfor asrc/lib/**change is ahighfinding.
The code itself is clean and consistent with witness-not-translator: ext is echoed verbatim on the submitted envelope in both settlement modes and projected on get_task_status/tasks_get/list_tasks, with tests covering echo, omit, and the decorating-registry read path. The only blocker is the missing changeset for the new public API surface — add a .changeset/*.md entry (minor, since this adds new optional public fields) to resolve.
Blocking findings
- (missing) .changeset/*.md — new public API (TaskHandoffOptions.ext, TaskRecord.ext) added under src/lib/** with no changeset; high per changeset-vs-wire-impact rule
Problem
A seller that hands off to a task often already knows a vendor-side identity for the work — an order number, a campaign page, a ticket — and wants the buyer to see it while the task is still
submitted. Today the framework leaves no compliant place for that:dispatchHitlhard-codes the submitted envelope as{ status: 'submitted', task_id }, although the spec's submitted branch (create-media-buy-response,sync-creatives-response, …) declaresext.get_task_status/tasks_get/list_tasksproject only spec fields off theTaskRecord, so a registry cannot add anything on reads either.resultis by spec the terminal artifact, so it cannot carry anything before completion.Change
TaskHandoffOptions.ext— an optional, vendor-namespaced extension object.dispatchHitlechoes it verbatim on the submitted envelope, in both settlement modes.TaskRecord.ext— projected asextbyget_task_status,tasks_getandlist_tasksitems. The built-in registries never persist it; a decorating registry attaches it at read time (that is how we use it: the media buy a booking task holds, read from our own ledger).Doc comments state the contract: keys sit under a vendor namespace (
ext.acme), never a spec field such asmedia_buy_id, which stays on the terminal artifact.Tests
server-decisioning-mock-seller: the envelope echoesextwhen the adopter passes one and omits it otherwise; no top-levelmedia_buy_idleaks.server-create-adcp-server: a decorating registry'sextshows up onget_task_statusand onlist_tasksitems.npm run buildand both suites pass (173 tests). Prettier clean.🤖 Generated with Claude Code