Skip to content

feat(signals,media-buy): cache-scope isolation for wholesale-feed conditional fetch#5748

Open
EvgenyAndroid wants to merge 3 commits into
adcontextprotocol:mainfrom
EvgenyAndroid:feat/wholesale-feed-cache-scope-isolation
Open

feat(signals,media-buy): cache-scope isolation for wholesale-feed conditional fetch#5748
EvgenyAndroid wants to merge 3 commits into
adcontextprotocol:mainfrom
EvgenyAndroid:feat/wholesale-feed-cache-scope-isolation

Conversation

@EvgenyAndroid

Copy link
Copy Markdown
Contributor

Closes #5739.

Problem

The wholesale-feed token is documented as scope-keyedget-signals-response.json
and get-products-response.json both say a caller caches
(cache_scope, wholesale_feed_version) pairs, not a global agent version. But
nothing in the conformance suite exercises that property: both
wholesale-feed-signals.yaml and wholesale-feed-products.yaml only ever drive
cache_scope: public, so an agent that keys conditional fetch on a
scope-independent token passes today.

The reference training agent demonstrates the gap directly. It advertises
wholesale_feed_versioning.cache_scope_account: true and resolves the reserved
account-overlay.example identity to cache_scope: account
(server/src/training-agent/task-handlers.ts), yet mints a scope-independent
token and compares only the token value — so a public-minted token echoed on
an account-scope read wrongly short-circuits to unchanged: true, and the
caller silently misses the account overlay.

Changes

  1. Schemas — a cross-scope MUST NOT appended to the unchanged description
    in get-signals-response.json and get-products-response.json, scoped to the
    conditional-fetch comparator: it MUST key on (cache_scope, wholesale_feed_version);
    a token minted for cache_scope: 'public' cannot match the agent's current token
    for cache_scope: 'account' (or vice-versa), so such a request MUST return the
    full feed for the resolved scope. This operationalizes the "scope-keyed" language
    already present in wholesale_feed_version.

  2. Storyboards — new universal wholesale-feed-signals-scope-isolation and
    wholesale-feed-products-scope-isolation, gated on
    wholesale_feed_versioning.cache_scope_account: true. Each bootstraps the public
    feed, captures the token, echoes it on a read the agent resolves to
    cache_scope: account, and asserts unchanged is absent, cache_scope: account,
    and rows are returned. Agents without per-account overlays grade not_applicable,
    not failed.

  3. Reference agent — scope-key the wholesale feed/pricing tokens (fold
    cache_scope into the token value). The same-scope unchanged path still matches,
    so existing wholesale storyboards are unaffected; the cross-scope path now differs.

Validation (local)

  • npm run build:compliance ✅ — 40 universal / 6 protocols / 21 specialisms
  • npm run test:schemas ✅ 19/0 · test:storyboard-branch-sets ✅ 23/0 ·
    test:storyboard-scoping ✅ 0 fail (parity with the training-agent handler map)
  • No storyboard or test asserts the literal token value, so scope-suffixing is safe.

On introduced_in: "3.2" (deliberate, not a backport)

This PR makes an existing 3.1 MUST testable — it does not add a new requirement.
The scope-keying contract is already in the 3.1 spec text (get-{signals,products}-response.json:
callers cache (cache_scope, wholesale_feed_version) pairs). On accuracy alone "3.1"
would be defensible.

It is nonetheless set to "3.2", matching the milestone, because the change is not
patch-eligible
: a previously-passing global-token build would newly fail the isolation
storyboard. Tightening an existing-but-untested MUST into a checkable conformance gate is
a minor-version event, so it lands as a 3.2.0 requirement rather than a 3.1 backport.
Single-scope agents (no cache_scope_account) grade not_applicable, so only agents that
actually publish account overlays are ever held to it.

…ditional fetch

Closes adcontextprotocol#5739.

The wholesale-feed token is documented as scope-keyed — a caller caches
(cache_scope, wholesale_feed_version) pairs — but nothing exercised that a
token minted under one cache_scope cannot short-circuit (unchanged: true) a
request the agent resolves to another. The reference training agent advertises
wholesale_feed_versioning.cache_scope_account: true yet keys conditional fetch
on a scope-independent token, so it would silently answer unchanged across
scopes.

- schemas: add a cross-scope MUST-NOT to get-signals-response /
  get-products-response `unchanged`, scoped to the conditional-fetch comparator.
- storyboards: new universal wholesale-feed-{signals,products}-scope-isolation,
  gated on cache_scope_account so public-only agents grade not_applicable.
- reference agent: scope-key the wholesale feed/pricing tokens.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@aao-release-bot aao-release-bot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Argus review could not complete

The automated review encountered an issue (possibly reached max turns, timed out, or failed to post the final gh pr review). A human reviewer should take this PR.

View workflow run

This is an automated message from the Argus AI review workflow.

…al parity tables

The universal-storyboard doc-parity lint (scripts/lint-universal-storyboard-doc-parity.cjs,
run inside build:compliance) requires every graded universal storyboard to have a row in
both the conformance index and the compliance catalog. Back-fill rows for the two new
wholesale-feed-{signals,products}-scope-isolation storyboards.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@aao-release-bot aao-release-bot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Argus review could not complete

The automated review encountered an issue (possibly reached max turns, timed out, or failed to post the final gh pr review). A human reviewer should take this PR.

View workflow run

This is an automated message from the Argus AI review workflow.

The reference agent now folds cache_scope into the wholesale feed/pricing
token (training-*-feed-v1 -> training-*-feed-v1.public[.<digest>]). Update the
literal expectations in the public-scope wholesale tests accordingly. The
standalone-pricing-token rejection cases keep their arbitrary literals (the
reject path is value-independent).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@aao-release-bot aao-release-bot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Argus review could not complete

The automated review encountered an issue (possibly reached max turns, timed out, or failed to post the final gh pr review). A human reviewer should take this PR.

View workflow run

This is an automated message from the Argus AI review workflow.

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.

Conformance: wholesale conditional-fetch has no cache_scope-isolation storyboard — global-token implementations pass the suite

1 participant