Skip to content

docs+compliance: terminal-buy carve-out (#4635) + dependency-impairment storyboard (#2860)#4677

Merged
bokelley merged 3 commits into
mainfrom
bokelley/triage-non-3-2-open
May 17, 2026
Merged

docs+compliance: terminal-buy carve-out (#4635) + dependency-impairment storyboard (#2860)#4677
bokelley merged 3 commits into
mainfrom
bokelley/triage-non-3-2-open

Conversation

@bokelley

Copy link
Copy Markdown
Contributor

Two 3.1.0 follow-ups from the #4601 cluster — finishing the impairment.coherence rollout.

Issues closed

Commits

  1. docs(compliance): make terminal-buy carve-out explicit for impairment.coherence health-iff rule — original lifecycle.mdx only relaxed the impairments[] reporting requirement on terminal buys; the impairments[]health biconditional was not explicitly relaxed. The runner in @adcp/sdk 7.6.0 (adcp-client#1801) already evaluates all three rules only against non-terminal buys; the spec text now matches. Mirrored on compliance-catalog.mdx.

  2. feat(compliance): dependency-impact end-to-end storyboard (#2860) — new media_buy_seller/dependency_impairment scenario with five phases against the comply test controller's sandbox:

    • setup — create active buy with creative assignment, force creative to approved baseline
    • baseline_healthyget_media_buys reports health: ok, impairments[] empty
    • transition_offlineforce_creative_status flips creative → rejected
    • verify_impairedget_media_buys reports health: impaired with a matching impairments[] entry (resource_type, resource_id, package_ids, transition.to all asserted)
    • recover_and_verify — flip creative back to approved, verify health: ok and impairments[] clears (exercises the biconditional both directions)

    Wired into protocols/media-buy/index.yaml#requires_scenarios so every media-buy seller storyboard run grades it. Sellers without comply_test_controller force_creative_status grade not_applicable.

Test plan

  • build:compliance
  • test:schemas ✓ / test:storyboard-{doc-parity,scoping,validations-paths,sample-request-schema,response-schema,check-enum,branch-sets,test-kits,context-entity,contradictions,provides-state-for,auth-shape,advisory-expiry,raw-mode-required}
  • Pre-push storyboard matrix ✓ (creative-track scenario passes against the training agent)
  • Mintlify broken-links + schema-links ✓
  • CI green
  • ⚠️ test:storyboard-context-output-paths has a pre-existing failure on sales-guaranteed/index.yaml unrelated to this PR (confirmed by stashing changes; same # fail 1). Should be filed/fixed separately.

Rollout notes

  • Spec change in commit 1 is a clarification — no behavior change for runners that already implemented the carve-out (the SDK 7.6.0 runner does).
  • Storyboard in commit 2 is creative-track only. Audience-track and catalog-track variants are follow-ups pending force_audience_status / force_catalog_item_status support in the compliance test controller.

🤖 Generated with Claude Code

bokelley and others added 3 commits May 17, 2026 14:30
….coherence health-iff rule

Original lifecycle.mdx text only addressed the impairments[] reporting
relaxation on terminal buys; the impairments[] ↔ health biconditional was
not explicitly relaxed. The @adcp/sdk 7.6.0 runner (adcp-client#1801)
already evaluates all three rules only against non-terminal buys; this
makes the spec text match.

Closes #4635.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
New media_buy_seller/dependency_impairment scenario — the cross-resource
exercise that drives non-NA grading of the impairment.coherence invariant
landed in #2859.

Five phases against the comply_test_controller sandbox:
  1. setup — create active buy with creative assignment, force creative
     to approved baseline
  2. baseline_healthy — get_media_buys reports health: ok, impairments[] empty
  3. transition_offline — force_creative_status flips creative to rejected
  4. verify_impaired — get_media_buys reports health: impaired with a
     matching impairments[] entry (resource_type, resource_id, package_ids,
     transition.to all asserted)
  5. recover_and_verify — force creative back to approved, verify health
     returns to ok and impairments[] clears (exercises the biconditional
     both directions — stale impairments fail this phase and the invariant)

Wired into protocols/media-buy/index.yaml#requires_scenarios so every
media-buy seller storyboard run grades it. Sellers without
comply_test_controller force_creative_status grade not_applicable.

Creative-track only today. Audience-track and catalog-track follow once
the controller adds force_audience_status / force_catalog_item_status.

Closes #2860.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three rounds of expert review (protocol, docs, product). Must-fix items
addressed:

Docs (lifecycle.mdx, compliance-catalog.mdx):
- Pull health-iff out of the inverse paragraph into its own named rule.
  'Out of scope' had referenced 'three rules' but only two were headlined.
- Tighten terminal-buy carve-out: spell out seller permission ('MAY leave
  impairments[] and health in whatever state held at the terminal
  transition') and buyer posture ('MUST NOT treat post-terminal drift as
  a coherence violation'). Replaces the looser 'biconditional likewise
  relaxes' framing.
- Align on 'iff' across both docs. Drop 'biconditional' and 'bidirectional
  biconditional' (terms-of-art drift across adjacent docs).

Storyboard (dependency_impairment.yaml):
- Add field_present asserts for the required impairment fields
  (impairment_id, reason_code, observed_at — all required per
  impairment.json but the per-step checks weren't catching their absence).
- Add field_value assert that impairments[0].package_ids[0] matches the
  buy's package_id — without this, a seller could list a different package
  and still pass the impairment-present check.
- Add field_value_or_absent: [] for impairments on baseline and recovery
  phases — health: ok with non-empty impairments[] should fail the
  health-iff rule, and the per-step check catches it independently of the
  cross-resource invariant.
- Align narrative on 'health-iff rule' (was 'bidirectional biconditional').

Deferred to follow-ups (filed separately):
- Cardinality assertion with a second creative (inverse-rule under
  cardinality pressure).
- Swap-assignment recovery variant (more realistic than approved →
  rejected → approved on the same creative_id).
- not_applicable escape valve for sellers that propagate via webhook with
  no health field on the buy.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@bokelley bokelley merged commit f2364d9 into main May 17, 2026
23 of 25 checks passed
@bokelley bokelley deleted the bokelley/triage-non-3-2-open branch May 17, 2026 19:25
bokelley added a commit that referenced this pull request May 18, 2026
… (#4733)

When a creative referenced by a media buy's package transitions to rejected,
the buy now surfaces `health: impaired` and an `impairments[]` entry. When the
buyer recovers via assignment swap (update_media_buy replacing the offline
creative with an approved sibling), the impairment clears and health returns
to ok. Closes the dependency_impairment + dependency_impairment_cardinality
storyboards added in #4677/#4685.

- types.ts: Impairment interface + MediaBuyState.impairments
- comply-test-controller.ts: propagateCreativeImpairment walks session.mediaBuys
  on forceCreativeStatus, appending on approved→rejected and removing on the
  inverse; idempotent on re-emission
- task-handlers.ts:
  - get_media_buys emits health + impairments mapped to wire shape
  - update_media_buy recomputes impairments after creative_assignments
    replacement; drops any whose resource_id is no longer referenced
- tenants/comply.ts: wire force_creative_status adapter on /sales (was missing,
  storyboards reported force_scenario_unsupported)

Scenario fixes:
- Both dependency_impairment storyboards restructure sync_creatives + inline
  assignments into sync_creatives + update_media_buy. v6 SalesPlatform.syncCreatives
  doesn't expose request-level assignments to the platform (filed upstream at
  adcp-client#1842). Both surfaces are spec-canonical; this is a v6-SDK
  compatibility choice, not a deprecation.
- dependency_impairment_cardinality also needs bid_price: 10.0 on its packages
  because its brief lands on an auction pricing_option as products[0].pricing_options[0]
  (test-design issue filed at #4732).

Sales floor lifts from 72:340 to 74:380.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
bokelley added a commit to adcontextprotocol/adcp-client that referenced this pull request May 18, 2026
…] in impairment.coherence

Closes two gaps in the storyboard runner's `impairment.coherence`
invariant exposed by the dependency-impairment storyboard
(adcontextprotocol/adcp#2860 / adcontextprotocol/adcp#4677):

1. **Audience leg of the inverse rule is now graded.** The buy-side
   reference lives at `packages[*].targeting_overlay.audience_include[]`
   — a stable, spec-defined field that lets the runner traverse buy →
   audience the same way it traverses buy → creative. `audience_exclude`
   is intentionally excluded — suspending an exclude-audience does not
   prevent the buy from serving. The inverse check is now parameterised
   over both reference sets (creative + audience); a suspended audience
   referenced by a non-terminal buy that doesn't list it in
   `impairments[]` now produces a `violation: 'inverse'` failing result,
   mirroring creative coverage. `audience` is removed from
   `INVERSE_DEFERRED_FAMILIES`; the `not_applicable` hint that used to
   fire on every audience offline transition stops firing — audience
   observations flow into the graded path.

2. **`creative_approvals[]` is now walked on buy snapshots.** The
   `get-media-buys-response.json` package shape uses `creative_approvals[]`
   (per spec) — different from `core/package.json`'s
   `creative_assignments[]` (the request-side shape). `readBuySnapshot`
   previously only walked the latter, which made the inverse rule for
   creative grade silent on conformant `get_media_buys` snapshots. Now it
   walks both. This was the bug that masked the v6 SalesPlatform
   gap surfaced in #1846 — without this
   extractor, the inverse rule grades silent on a properly-shaped buy
   snapshot even when the creative is referenced.

Test coverage: 6 new tests — 5 audience inverse coverage cases (graded
propagation, exclude-doesn't-count, terminal carve-out, recovery clears,
paired with health-iff) + 1 creative_approvals extraction case. Existing
deferred-family test loop moves audience out and asserts the graded
behaviour. The onEnd partial-coverage summary still flags catalog_item
and event_source — their per-buy reference shapes remain unstable.

No behaviour change for storyboards that already propagate impairments
correctly — they previously graded `not_applicable` for audience offline
observations and now grade `pass` instead. Storyboards that observed an
audience transition without propagating it to a buy snapshot previously
graded silent (with a `not_applicable` notice) and now FAIL with a
structured `impairment_coherence_violation` hint pointing at the offline
audience.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
bokelley added a commit to adcontextprotocol/adcp-client that referenced this pull request May 18, 2026
…] in impairment.coherence (#1848)

* feat(testing): grade audience inverse rule + walk creative_approvals[] in impairment.coherence

Closes two gaps in the storyboard runner's `impairment.coherence`
invariant exposed by the dependency-impairment storyboard
(adcontextprotocol/adcp#2860 / adcontextprotocol/adcp#4677):

1. **Audience leg of the inverse rule is now graded.** The buy-side
   reference lives at `packages[*].targeting_overlay.audience_include[]`
   — a stable, spec-defined field that lets the runner traverse buy →
   audience the same way it traverses buy → creative. `audience_exclude`
   is intentionally excluded — suspending an exclude-audience does not
   prevent the buy from serving. The inverse check is now parameterised
   over both reference sets (creative + audience); a suspended audience
   referenced by a non-terminal buy that doesn't list it in
   `impairments[]` now produces a `violation: 'inverse'` failing result,
   mirroring creative coverage. `audience` is removed from
   `INVERSE_DEFERRED_FAMILIES`; the `not_applicable` hint that used to
   fire on every audience offline transition stops firing — audience
   observations flow into the graded path.

2. **`creative_approvals[]` is now walked on buy snapshots.** The
   `get-media-buys-response.json` package shape uses `creative_approvals[]`
   (per spec) — different from `core/package.json`'s
   `creative_assignments[]` (the request-side shape). `readBuySnapshot`
   previously only walked the latter, which made the inverse rule for
   creative grade silent on conformant `get_media_buys` snapshots. Now it
   walks both. This was the bug that masked the v6 SalesPlatform
   gap surfaced in #1846 — without this
   extractor, the inverse rule grades silent on a properly-shaped buy
   snapshot even when the creative is referenced.

Test coverage: 6 new tests — 5 audience inverse coverage cases (graded
propagation, exclude-doesn't-count, terminal carve-out, recovery clears,
paired with health-iff) + 1 creative_approvals extraction case. Existing
deferred-family test loop moves audience out and asserts the graded
behaviour. The onEnd partial-coverage summary still flags catalog_item
and event_source — their per-buy reference shapes remain unstable.

No behaviour change for storyboards that already propagate impairments
correctly — they previously graded `not_applicable` for audience offline
observations and now grade `pass` instead. Storyboards that observed an
audience transition without propagating it to a buy snapshot previously
graded silent (with a `not_applicable` notice) and now FAIL with a
structured `impairment_coherence_violation` hint pointing at the offline
audience.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(impairment.coherence): reframe audience_exclude as serviceability not safety

Spec review caught a framing issue: prior comments described the
exclusion of audience_exclude as "doesn't prevent the buy from serving"
which is true but conflates serviceability with safety. An offline
exclude-audience can still silently break the suppression promise —
that's a separate (forward-looking) signal class, not a reason to call
excludes harmless.

Also drops temporal "previously"/"prior to adcp#2860" framing from
comments per CLAUDE.md and trims the #1846 internal-bug reference
from the public changeset.

No behaviour change.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant