Repository navigation
[spec] ctx_token binds to click-out content_engaged event; share it on resolve with turn/session totals under partial visibility #28
Description
Specification section
§6.4 (tokens_ingested), §6.5 (excerpt_tokens), §6.6 (content_displayed), §6.7 (content_engaged), §7.1 (ctx_token resolve / click manifest), §7.3 (routing / owner-filtered views).
What you observed
ctx_token resolves to a session, not to a specific click
Section 7.1 defines ctx_token resolution as exposing the click manifest for the owning session: gated content_grounded, content_cited, and content_displayed. The token is not defined as identifying a particular click-out.
Without a bind to a specific engagement, resolve cannot place the click in time inside the chat. Recipients do not know whether the user left on the first answer, after several turns of refinement, or clicked early and kept talking afterward. Those cases imply different influence windows — yet two tokens from the same session can return the same whole-session manifest, with no signal for which destination, which turn, or which moment in the dialogue the click belonged to.
content_engaged belongs on the session, but it is not part of the click manifest. The specification does not require consumers to expose it on resolve; sharing is operator-defined. A resolve-only party gets a gated source list with no engagement event and no standard join from token → “this click at this point in the conversation.”
No turn- or session-wide totals when only some sources are visible
Each visible source carries its own counts (tokens_ingested, excerpt_tokens), but nothing says how large the whole turn or session was — total tokens across all sources, or how many distinct sources were grounded, cited, or displayed. Without those overall totals, a recipient who only sees a subset of sources cannot compute each source’s share of the context, the citations, or the clickable UI surface.
content_displayed is a separate stage from content_cited (§4.3 / §6.6): they might co-occur for the same URL, but display without citation and citation without a display event are both valid. Click-out competition is about what was shown, not only what was cited — yet display has the same partial-visibility problem and no denominator today.
Scenario A — Consent-gated click manifest. Resolve returns only opted-in sources. If five sources grounded and two appear, recipients see absolute counts for those two only. They cannot tell whether the two dominated the mix or were a small slice — and may over-credit them. The same applies when two of twelve links were displayed.
Scenario B — Own-event stream. Under §7.3, publishers (and networks on their behalf) receive only their own content_grounded / content_cited / content_displayed events. Peer sources are not disclosed. From that stream alone, 800 tokens could be most of the context or a small fraction, and one source could be 1 of 2 or 1 of 20 among grounded, cited, or displayed items.
A party with the full ungated session could sum tokens and count distinct sources; under consent gating or owner isolation that information is unavailable. There is no existing field for those totals.
Why it matters
Click-out attribution is about a specific user action at a specific point in the conversation, not just “somewhere in this chat.” Binding the ctx_token only to the session_id blurs multiple clicks together and obscures whether the click happened early or late in the dialogue. Without an overview about display, citation, and grounding at the moment of the click, it becomes extremely difficult to accurately calculate attribution weight—you can't assess how relevant or prominent each citation, grounding, or display event was up to the time of the click.
Fair pay and flexible weighted models also need those overall turn/session totals next to each source’s own counts. Without them, you can re-weight the visible set but cannot tell whether those sources dominated or were a small slice — by tokens, by source count, or by how crowded the displayed / clickable surface was.
Delivering the agent-authored click-out content_engaged to the destination content owner (when that owner participates in telemetry) is equally important. It gives the owner a reliable click signal from the agent itself, reduces dependence on the ctx_token surviving every redirect hop to the landing page, and moves the engagement record from the agent to the owner without requiring the owner to call resolve on the telemetry consumer. Destination-side or network corroboration remains useful, but the owner should not depend on token transport or consumer lookup alone to learn that the click happened.
Proposed direction (optional)
1. ctx_token maps to a specific click-out content_engaged
Change §7.1 so lookup returns the click-out engagement as well as the session:
Today: ctx_token → gated manifest (whole session)
Proposed: ctx_token → content_engaged (this click)
+ gated manifest (whole session)
Therefore, the agent operator MUST issue a content_engaged event to register the user action. Additionally, if the click-out destination (for example, advertiser.com) is an entity that has registered to receive telemetry events—such as content_grounded or content_cited—the agent MUST send the content_engaged event to that entity as well.
2. Turn and session totals (token and source-count)
Add turn- and session-wide totals so a recipient with only a subset of sources can still compute share. Totals MUST count every contributing source (including those omitted from a gated manifest or owner-filtered stream). Recipients learn the numbers only — not peer URLs or publishers.
Scope
| Aggregate | Covers |
|---|---|
| Turn | All grounded / excerpt tokens and distinct grounded, cited, and displayed sources in this turn |
| Session | Aggregates across turns. On content_engaged: all turns that existed at click time (1..M), not only through the click’s turn_id (N) |
Fields to add to content_grounded, content_cited, content_displayed, and content_engaged events
| Tokens | Distinct sources | |
|---|---|---|
| Grounded | {turn|session}_total_tokens_grounded |
{turn|session}_total_sources_grounded |
| Excerpt (cited) | {turn|session}_total_excerpt_tokens |
{turn|session}_total_excerpt_sources |
| Displayed | — (no token fields on §6.6) | {turn|session}_total_sources_displayed |
Alongside the token/source totals above, click-out content_engaged MUST carry both of the following so recipients can place the click in the dialogue:
| Field | Meaning |
|---|---|
| Turn ordinal N | Which turn the engaged link came from. Today §5.2.1 allows turn_id to be any emitter-defined string (sequential integer, UUID, opaque id). “Turn N of M” only works if N is ordered and comparable to session_total_turns, so the spec MUST either require turn_id to be a sequential integer string ("1", "2", …) or add a dedicated turn_index (0- or 1-based ordinal). This issue assumes sequential turn_id / turn_index = N. |
session_total_turns (integer, new) |
How many turns existed in the session at click time (M). Session window for session totals is turns 1..M, not only through N. |
Together these express “turn N of M at click time.” Example: user is on turn 5 of a 5-turn session but clicks a link from turn 2 → turn ordinal = 2, session_total_turns = 5.
Distinct sources counts unique content items, not events. Key by content_id when present, otherwise content_url. Example: the same URL appears in two content_grounded rows → that is 2 events but 1 source toward *_total_sources_grounded. Token totals still sum every event; source-count fields count each content item once.
Where they appear
All the different totals (grounded, excerpt and display) are added to each event (content_grounded, content_cited, content_displayed, and content_engaged). Grounded without cited, cited without display, and display without citation are all valid under the spec. Shipping only grounded totals on a content_grounded event, for example, leaves a publisher unable to tell whether they dominated the answer mix or were one of twelve links in the sidebar. Putting all three group of totals on each event (content_grounded, content_cited, content_displayed, and content_engaged) is how a content owner (or a network on their behalf) gets a full overview of prominence without seeing peer URLs.
Payload cost is small: a handful of integers (token totals + distinct source counts, turn + session). Peers are not disclosed.
| Event | Details |
|---|---|
content_engaged (click-out) / resolve |
MUST carry the full grounded + cited + displayed turn/session totals at click time. This is the authoritative “importance” snapshot for attribution: turn N of M; turn totals for the turn the click came from (N), and totals over all turns available at click time (1..M) — including turns after N when the user clicked back to an earlier answer, excluding turns that only happen after the click. |
content_grounded / content_cited / content_displayed |
Each event carries own contribution vs turn/session totals as of that event, without seeing peer sources. Display events carry source-count totals only. |
3. Consequences
3.1 ctx_token binding and resolve
- Each outbound click gets its own
ctx_tokenbound to the agent-authoredcontent_engagedissued for that action. content_engagedevent MUST includeturn_idandsession_total_turnsat click time (turn N of M).- Looking up the token MUST return that engagement event (no longer operator-optional) and plus the gated whole-session manifest.
- If a destination or network also reports
content_engagedfor the samectx_token, that report MAY be merged into the agent-authored engagement (one resolved event) rather than returned separately. A boolean such ascorroborated_click(or equivalent) MAY mark that arrival was independently observed. - Resolve still returns the session’s gated citation chain (the manifest) alongside the engagement — not the engagement alone.
- The agent-authored
content_engagedMUST also be delivered to the destination content owner when that destination participates in telemetry (same routing/isolation as other owner-scoped events under §7.3) — so the owner is notified of the click without depending on destination-side reporting or resolve alone.
3.2 Totals under partial visibility
- Turn and session totals for all three stages (grounded, cited, displayed) MUST appear on the resolved
content_engaged. Displayed: source-count fields only. - On stage events (
content_grounded/content_cited/content_displayed): include the full three-stage (grounded, cited, displayed) turn/session totals - On
content_engaged: all ofturn_id,session_total_turns, turn totals, and session token/source totals (including*_total_sources_displayed) are written at click time (session window = turns 1..M then) and immutable thereafter. Oncontent_grounded/content_cited/content_displayedevents: totals are immutable from emit. Resolve MUST NOT rewrite any of these. - Totals MUST include every contributing source (including gated or owner-filtered peers). Recipients get counts only — not peer URLs or publishers.
- With own-source counts plus these totals, a recipient under partial visibility can compute share of context (tokens / grounded sources), of citations (excerpt tokens / cited sources), and of the displayed UI surface (displayed sources) without seeing the rest of the mix — i.e. a publisher-grade overview of how important their content was in that turn/session.
Your perspective
None
Activity
jalexspringer commentedon Jul 26, 2026
Accept the click-binding point for v1. Each outbound click should get a unique
ctx_token, bound to the exactcontent_engagedevent and presentation. Resolution should return that engagement and its relevant context, not the whole session indiscriminately.I would not add turn/session totals to every event. Early events cannot contain final citation or presentation totals, repeated snapshots could leak hidden activity, and “importance” is a commercial interpretation. We can consider a privacy-bounded summary at resolution time separately.
pedroamaralsantos commentedon Jul 30, 2026
First of all thanks for your review and input.
Could you clarify what exactly you mean by relevant context?
The whole section would be nice to have, but at least the events that occur until click time would be important. And as described in the issue the cut should be by click timestamp, not by click turn alone. If the user clicks during turn 5 while 10 turns already exist, resolve should include all events from turns 1..10. Limiting until the click turn only would drop relevant context/events that might have contributed to the user engagement. Post-click activity can be excluded.
That is already a privacy improvement over the initial whole-session proposal. Each event should carry a
turn_idso recipients can analyze per-turn contributions. On the boundcontent_engagedevent,turn_id+session_total_turns_at_click(turn N of M) remain essential to place the click within the dialogue (e.g., clicked in turn 10 of 10 vs. turn 2 of 10). This ensures that all events which influenced the user's click are included, allowing for a better understanding of the user journey and, consequently, more accurate attribution models.Agent-authored
content_engagedto the destination owner — critical for attribution without depending on resolve via the telemetry consumerThis point was not addressed in your reply, and it is important to us: the agent-authored click
content_engagedevent MUST be delivered to the destination content owner when they are participating in telemetry (§7.3 owner-scoped routing), with thesession_idincluded in the server-side delivery—just like grounding/citation events today. In fact, if we include this in the specification, issue #29 becomes less significant, because having the session id in the server-side events would allow the receiver to connect a click event to their session events without needing to call resolve. Meanwhile, thectx_tokenin the redirect URL remains opaque and resolution-dependent for parties who only see the click chain (the ctx token). We see this as a major step toward publisher empowerment (#29), without weakening the query-string privacy boundary. What are your thoughts on including this in v1?Turn/session totals — on each event
Our proposal does not require final session totals on every row. Each event would carry session aggregates through the turn it belongs to (turns 1..N), frozen at emit time. That gives a denominator at a defined point in time, not a moving snapshot of the full finished session.
Recipients can compute explicit ratios from their own fields — e.g.
excerpt_tokens / session_total_excerpt_tokens— without seeing peer URLs.Example — publisher joins grounding, citation, and click via
session_idScenario: 5 turns exist at click time. Publisher A is grounded in turn 2 and cited in turn 3; user clicks A’s link (from turn 4) during turn 5. Publisher A receives only owner-scoped events:
Event 1 —
content_grounded(turn 2, emit time)Event 2 —
content_cited(turn 3)Event 3 —
content_engaged(click, same session, server-side delivery)Publisher A — computed shares (no resolve, no peer URLs)
Join on
session_id+content_url:What this shows: Each event carries the publisher’s own contribution (e.g.
tokens_grounded,excerpt_tokens) plus session denominators at that emit time. From those fields alone, the publisher can compute the shares above — grounded, cited, and displayed — at ground time, cite time, and click time, without resolve or peer URLs. The absolute contributions stay fixed; the ratios change as the session grows. Those ratios are objective, measurable inputs; how they are weighted in payment or attribution is a separate, commercial decision.Without totals, a publisher knows they contributed, but not how much (800 excerpt tokens out of how many?). Totals are analytics, not commercial rules in themselves — but they enable fairer, more complex attribution models, because parties can use that data to build payment/commercial logic on top.
On the concern that repeated snapshots could leak hidden activity — we would like to understand your view better. Our totals are fully aggregated (integer counts only, no peer URLs or identities). In the general case, a publisher only learns that the session mix grew (e.g. from turn 2 → turn 3 → click), not who was added. The one edge case we do see: with only two contributors in a stage,
session_total − own_contributionreveals the exact size of the other contribution (still not its identity). We do not see that as a critical leak, as it exposes a volume only in a narrow two-party case — not who contributed.We are open to alternative designs(maybe add some noise to the values?). At the same time, it is important to us that publishers can compute share/ratio from their own event stream — at click time for conversion attribution, and at each event emit time for ongoing analysis — without depending on the telemetry consumer.
About your suggestion, deferring totals to resolve time only may help address privacy, but it reintroduces dependency on the telemetry consumer — the same gatekeeper problem as #29. Even when resolve works, every attribution question flows through the session-holding party, subject to access, consent gating, and operational availability. We would prefer a design where publishers can compute shares from owner-scoped server-side events alone (grounding, citation, display, and agent-authored
content_engaged), and treat resolve as a complement for parties that only see the click chain (ctx_token).What are your thoughts? Thank you
jalexspringer commentedon Aug 12, 2026
Thanks — answering the "relevant context" question directly.
Resolution returns the lineage of the clicked reference, not a time-slice of the session. Concretely: the
content_engagedevent the token is bound to; its presentation record; the citation(s) that presentation realises; and the grounding events for that same content in the turns that produced it. That is the context a publisher needs to interpret the click, and every event in it is one the publisher's content participated in.A cut "all events from turns 1..10 at click timestamp" returns the whole session through any one click, including grounding and citation of other publishers' content the clicking publisher never touched. That re-imports the leak the privacy boundary exists to prevent, and repeated clicks would stream session state to whoever holds any token. Cross-content session totals are a commercial aggregate, and belong to reporting-level delivery under the SPUR profile rather than per-click resolution.
What I will take from your point: the lineage must not be cut by turn. A click in turn 5 on content grounded in turn 2 and re-presented since resolves the full lineage of that content across turns, by content identity rather than by turn or timestamp. The design note covering #23, #28 and #30 will specify the response shape with exactly that rule, plus a privacy-bounded summary option at resolution time (counts, not events) for the partial-visibility case you describe.
jalexspringer commentedon Aug 12, 2026
The click-context change is up as PR #38: one change covering token pattern and per-presentation binding, the reserved
ctx_token/ctx_issquery parameters with redirect propagation, manifest-declared resolution (telemetry.ctx_resolution), and the resolution response specified as the engagement plus the clicked content's lineage by content identity across turns, with an optional count-based session summary. Review welcome there before the 21 August freeze.Click context: gated contributing sources; owner-scoped engagement de…
Define the click context: ctx_token issuance, carriage, discovery and…
Click context: gated contributing sources; owner-scoped engagement de…
jalexspringer commentedon Sep 2, 2026
Landed in v1.0: per-presentation minting and click binding (7.4.1), content-identity lineage and the count-based session summary (7.4.4), owner-scoped delivery of the agent-authored engagement (7.4.5). Closing.