Skip to content

spec: add an optional change feed (GET /changes) for index-time federation (#96) - #108

Open
kperry-godaddy wants to merge 2 commits into
ards-project:mainfrom
kperry-godaddy:spec/96-change-feed
Open

kperry-godaddy wants to merge 2 commits into
ards-project:mainfrom
kperry-godaddy:spec/96-change-feed

Conversation

@kperry-godaddy

@kperry-godaddy kperry-godaddy commented Oct 12, 2026 •

Copy link
Copy Markdown

Normative text for the change feed proposed in #96. One optional endpoint, GET /changes: an ordered, cursor-driven, replayable feed of the identifiers a registry added, updated, or removed, and nothing else. A consumer fetches each entry from the identifier's authority (the <publisher> domain, resolved as §5.1 directs) and confirms every delete there. The feed says what exists and what changed; the authority says what the entry says.

What changes

  • spec/ard.md
    • New §5.6 Change Feed (GET /changes) — Optional: request, response, change object, cursor and delivery rules, the retention window, producer rules, consumer rules, security, errors. Placed after §5.5 Observability (merged from main) so it does not renumber §5.3.x (PR Add direct catalog entry lookup by identifier #74 adds there).
    • §5 intro names the new layer; §5.2 gains a "Change-Feed Subscription (Optional)" pipeline bullet; §5.4 gains one paragraph naming query-time and index-time federation and stating that federation: none keeps its meaning.
    • Appendix B adds 410 CURSOR_EXPIRED and names 501 NOT_IMPLEMENTED (Explore already returns 501 without a code).
    • D.3 lists GET /changes among the OpenAPI-defined interfaces. D.4 is untouched: conformance tooling is a follow-up PR.
  • spec/schemas/ard.openapi.yaml: /changes path (cursor, limit; 200/400/401/410/429/501/500), a ChangeFeedResponse schema referencing the new JSON Schema the same way SearchResultItem references ard-entry.schema.json, and a 410CursorExpired response. info.version left for the publishing commit.
  • spec/schemas/ard-change.schema.json (new): Cursor, Change, ChangeFeedResponse. Validated against the 2020-12 metaschema and against the §5.6.2 example plus negative cases.
  • spec/schemas/ard.cddl: cursor, change, changes-response.
  • adr/0011-index-time-federation-change-feed.md (new): context, decision, why identifiers rather than entries, alternatives, exclusions, consequences. Numbered after the merged ADR-0010; renumber if Add direct catalog entry lookup by identifier #74 lands first.

Decisions taken on the open questions in #96

Question What this PR does
Q1 identifiers only Yes. A change is {cursor, op, time, identifier}; the change object is closed (additionalProperties: false).
Q2 optional vs required Optional with 501, as for Explore; a registry operated as an upstream for other registries SHOULD implement it. One sentence; easy to drop if the group prefers plain optional.
Q3 retention Sliding window that MUST contain every held identifier, met either by indefinite retention (never 410, retention omitted) or by re-emitting an identifier's latest change before it ages out. Floor: SHOULD P7D. Cursor older than the window → 410 CURSOR_EXPIRED → staged replay; the live index is never emptied.
Q4 unreachable authority A delete is never applied while the authority cannot be reached; how long an entry then survives is the same question §5.2 leaves open for crawled entries, and the text says so rather than inventing a lifetime here.

Deliberately not in this PR

Checks

  • OpenAPI parses; every $ref (internal and to both JSON Schema files) resolves.
  • JSON Schema passes the Draft 2020-12 metaschema; the §5.6.2 example validates; unknown op, extra properties, bad cursors, bad durations, and >1000 changes are rejected.
  • Conformance demo still passes (it does not read the changed files; included as a smoke test).

Closes nothing on its own; tracks #96. Related: #63, #87, #88, #94, PR #74.

🤖 Generated with Claude Code

…ation (ards-project#96)

New §5.5 defines an ordered, cursor-driven, replayable feed of the
identifiers a registry added, updated, or removed. The feed carries no
entry content: a consumer fetches each entry from the identifier's
publisher domain (§5.1) and confirms every delete there, so the trust
rules are unchanged from crawling and mutually subscribed registries
converge without a hop list. Cursors are opaque; delivery is
at-least-once, latest change per identifier; the retention window must
contain every held identifier, so a new consumer replays it once with no
snapshot endpoint and no 410 mid-replay. Optional, 501 like Explore.

Also: the §5 intro names the new layer; §5.2 gains a change-feed
subscription pipeline bullet; §5.4 gains a paragraph naming query-time
and index-time federation; Appendix B gains 410 CURSOR_EXPIRED and names
501 NOT_IMPLEMENTED; D.3 lists the endpoint. The OpenAPI definition
gains /changes and a 410 response; ard-change.schema.json defines the
page and change objects and ard.cddl restates them. ADR-0011 records the
decision, the alternatives, and what was deliberately left out.

Identifier forms whose authority is not a publisher domain, and the
conformance tooling for producers and consumers, are left to follow-up
PRs.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Upstream added §5.5 Observability (Informative) in the position this
branch used for the change feed. Keep the observability section as
§5.5 and move the change feed to §5.6, renumbering its subsections
(5.6.1–5.6.8) and every cross-reference in spec/ard.md, ADR-0011, and
ard-change.schema.json. No text from either side is dropped.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@rvguha

rvguha commented Oct 29, 2026 via email

Copy link
Copy Markdown
Contributor

@kperry-godaddy

Copy link
Copy Markdown
Author

@rvguha - Thanks for the feedback.

  • This endpoint is optional. Implementers of ARD don't need to implement it.
  • Systems like AGNTCY and ANS already provide some type of sync/event feeds. This just puts them in a standard format everyone can consume. This can be the bridge between different systems.
  • Fan-out at query time is not scalable.

This branch has not been deployed

No deployments
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.

2 participants