Skip to content

JSON Schemas for change-feed event payloads (catalog + registry) #4792

@bokelley

Description

@bokelley

Why

Both specs/catalog-change-feed.md (landed in PR #4767) and specs/registry-change-feed.md (shipped) define event payload shapes in markdown prose + examples only — there is no static/schemas/source/core/catalog-event.json or per-event-type schema for product.priced, signal.priced, *.removed, catalog.bulk_change, applies_to, removal_reason, previous_pricing_option_ids, etc.

Surfaced during second-pass review of PR #4767. Quote: "the capability stanza enumerates event types but no schema exists. Without a schema, conformance runs can't validate event payloads and removal_reason is unenforced."

The catalog feed and registry feed share this gap. Spec'ing them together keeps the two surfaces parallel.

Scope

Catalog feed (PR #4767 surface)

Define a discriminated core/catalog-event.json keyed on event_type:

  • product.created, product.updated, product.priced, product.removed
  • signal.created, signal.updated, signal.priced, signal.removed
  • catalog.bulk_change

Each event payload needs:

  • event_id (UUID v7), event_type, entity_type, entity_id, created_at
  • Type-specific payload union, validating fields like:
    • applies_to: { scope: \"public\" | \"account\", account_ids?: string[] } — discriminator on scope
    • removal_reason enum: withdrawn / cancellation / expired / depublication / policy_takedown
    • previous_pricing_option_ids: string[]
    • changed_fields: string[]
    • effective_at: string (date-time)
    • For *.updated / *.priced: full or partial entity payload
    • For catalog.bulk_change: summary, affected_entity_types[], affected_count, recommendation

Conformance: response from GET /catalog/events validates against the schema; SDKs (@adcp/client's CatalogSync) consume the schema rather than parsing prose.

Registry feed (existing, parallel work)

Same treatment for the events in specs/registry-change-feed.md:

  • property.created, property.updated, property.merged, property.stale, property.reactivated
  • agent.discovered, agent.removed, agent.profile_updated, agent.compliance_changed
  • publisher.adagents_changed
  • authorization.granted, authorization.revoked

The registry feed's agent.compliance_changed and authorization.granted payloads are the most field-heavy (tracks, storyboards, full authorization scoping model) — those are the priority for schema treatment because consumers (TMP routers, RegistrySync clients) make routing decisions off them.

Acceptance

  • core/catalog-event.json + per-event-type variants live in static/schemas/source/core/
  • core/registry-event.json + per-event-type variants ditto
  • GET /catalog/events and GET /api/registry/feed responses cite the event schemas
  • Conformance assertion: events in storyboard fixtures validate against schemas
  • SDK type generation picks up the new schemas (TS first, then Go and Python)

Dependencies

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    claude-triagedIssue has been triaged by the Claude Code triage routine. Remove to re-triage.schemaJSON Schema source-of-truth: definitions, codegen artifacts, validation, hygiene

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions