Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@ repository = "https://github.com/openattribution-org/telemetry-server"
content-telemetry-core = { path = "crates/content-telemetry-core" }

axum = "0.8"
base64 = "0.22"
chrono = { version = "0.4", features = ["serde"] }
dashmap = "6"
rand = "0.8"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
sqlx = { version = "0.8", features = [
Expand Down
29 changes: 18 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,13 @@ curl -s -X POST localhost:8080/events \
-H 'content-type: application/json' -H "x-organization-id: $ORG" \
-d '{
"document_type": "event_batch",
"schema_version": "0.1",
"schema_version": "1.0",
"session_id": "'"$SESSION"'",
"events": [
{"type": "content_grounded",
"timestamp": "2026-08-06T12:00:00Z",
"content_url": "https://example.com/article-1",
"data": {"grounding_scope": "session"}}
"data": {"scope": "session"}}
]}'

curl -s "localhost:8080/sessions/$SESSION/document" -H "x-organization-id: $ORG"
Expand All @@ -78,7 +78,7 @@ disclosure and document materialisation — against a live build.
| `GET` | `/sessions/{id}/document` | The session as a standard session document |
| `POST` | `/events` | Ingest events, singly or in batches of up to 500 |
| `POST` | `/click-tokens` | Mint a ctx token for a click-out |
| `GET` | `/ctx/{token}` | Resolve a ctx token to its click manifest |
| `GET` | `/ctx/{token}` | Resolve a ctx token to its click context |

Events bind to a session in this order: the event's own `session_id`, the
batch's, the event's `ctx_token`, the batch's, and otherwise nothing —
Expand All @@ -103,8 +103,8 @@ No handler changes, because no handler knows how the answer was reached.

The exception is `GET /ctx/{token}`, deliberately unauthenticated: the
destination of a click-out has no account here. The token is the credential,
and what it discloses is bounded by two-sided consent and by a manifest shape
that never contains the session id.
and what it discloses is bounded by two-sided consent and by a click-context
shape that never contains the session id.

## The database

Expand All @@ -123,12 +123,19 @@ others.

## Conformance

Ingest enforces the v1 structural rules: `content_cited`, `content_presented`
and `content_reproduced` carry an event id and an `output_id`;
`content_engaged` carries the `presentation_id` of the presentation it acted
on; content events carry a resolvable `content_url` or `content_id`. The
`content_displayed` type v1 withdrew is refused rather than rewritten into a
claim the emitter never made.
Ingest enforces the v1 structural rules on documents declaring
`schema_version` `"1.0"`: `content_cited` and `content_presented` carry an
event id and an `output_id`; `content_grounded` carries `data.scope`;
`content_cited` carries `data.citation_type`; `content_retrieved` carries
`source_role`; `content_engaged` carries the `presentation_id` of the
presentation it acted on; content events carry a resolvable `content_url` or
`content_id`. Documents still declaring `"0.1"` are accepted for the
transition and normalised under the specification's migration rules instead.
The `content_displayed` type v1 withdrew is refused rather than rewritten
into a claim the emitter never made. `content_reproduced`, which never made
it out of the pre-release draft, is no longer a core type: rows stored under
it are treated like any other extension event and quarantined under the
document's `extensions` member.

Two things are stored as given rather than validated, because the
specification says a consumer must not reject a document over either:
Expand Down
2 changes: 2 additions & 0 deletions crates/content-telemetry-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@ repository.workspace = true
path = "src/lib.rs"

[dependencies]
base64.workspace = true
chrono.workspace = true
dashmap.workspace = true
rand.workspace = true
serde.workspace = true
serde_json.workspace = true
sqlx.workspace = true
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
-- v1 event fields the original schema predates.
--
-- ctx_token (specification section 5.2, 7.4.1): on an agent-reported
-- content_engaged event, the click token minted for that engagement's
-- presentation, recorded so destination reports can be joined to it at
-- resolution. The token-to-presentation binding is issuer state and this
-- column is where it survives.
--
-- terms_ref (specification section 5.2.4): reference to the governing terms
-- the emitter associates with the event. A processor MUST preserve it
-- unchanged - it is stored and served byte-for-byte, never normalised.

ALTER TABLE events ADD COLUMN IF NOT EXISTS ctx_token TEXT;
ALTER TABLE events ADD COLUMN IF NOT EXISTS terms_ref TEXT;

-- Destination reports join to the agent-recorded engagement by token.
CREATE INDEX IF NOT EXISTS idx_events_ctx_token ON events(ctx_token) WHERE ctx_token IS NOT NULL;
4 changes: 2 additions & 2 deletions crates/content-telemetry-core/profiles/rsl-1.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,15 +51,15 @@
{
"id": "grounding_scope",
"kind": "field_coverage",
"spec_ref": "standard s5.7.2",
"spec_ref": "standard s6.4",
"data_field": "scope",
"applies_to": ["content_grounded"],
"description": "content_grounded events carry data.scope."
},
{
"id": "citation_type",
"kind": "field_coverage",
"spec_ref": "standard s5.7.3",
"spec_ref": "standard s6.5",
"data_field": "citation_type",
"applies_to": ["content_cited"],
"description": "content_cited events carry data.citation_type."
Expand Down
Loading
Loading