Record the agreed human-presence mechanism for analysis summaries - #260
Merged
Merged
Conversation
…cked The website session and I settled FR-013. Presence rides as claims on the caller token they already mint, set only when their Turnstile-backed identity cookie validated on the request: `human` (absent rather than false, so a missing claim and a failed check look the same to us), `human_iat` for freshness, and `subject`, a random 16-byte value, for per-person throttling. Freshness is 30 minutes and both sides enforce it -- they refuse to mint past it, we refuse to accept past it -- so neither is a single point of failure. The claim's lifetime is deliberately shorter than the token's, because an HMAC cookie is a bearer credential and a long-lived presence claim is a durable bot pass with extra steps. They first proposed gating on the analysis token instead, on the grounds that running an analysis is real work already done and so decent evidence somebody meant it. That is sound for abuse resistance and wrong for this requirement, which is about consent. A token proves an analysis happened, not that a person is present, and not that the person present is the one who ran it -- analysis tokens travel in URLs people paste into tickets and papers. Worse, FR-011 and FR-012 make summarising opt-in with a choice of disclosure tier, and a choice a bot holding a forwarded link can make is a consent mechanism that consents on the user's behalf. That is worse than offering no choice, because it looks like one. They agreed and withdrew it. Their rate-limiting caveat is adopted as its own task: per token and per caller regardless, because a token asking for twenty summaries of one analysis is not a scientist. It is a throttle, not evidence of a person. T031 is done. T031a-c are the work it implies. One external dependency remains and it is theirs: their proxy mints caller tokens for the answer route only, so a summary route must exist before any claim can be carried. Nothing here assumes the browser calls us directly -- it cannot, the cookie is same-site to their origin. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
adamjohnwright
force-pushed
the
docs/011-human-presence-agreed
branch
from
September 19, 2026 03:49
f56fbcf to
1b7930b
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Settles FR-013 with the website session, and unblocks spec 011 Phase 8.
Presence rides as claims on the caller token they already mint, set only when their Turnstile-backed identity cookie validated:
human(absent rather than false, so a missing claim and a failed check are indistinguishable to us),human_iatfor freshness, andsubject— a random 16-byte value — for per-person throttling.Freshness is 30 minutes, enforced at both ends. They refuse to mint past it; we refuse to accept past it. Neither side is a single point of failure. The claim's lifetime is deliberately shorter than the token's, because an HMAC cookie is a bearer credential and a long-lived presence claim is a durable bot pass with extra steps.
The proposal that was withdrawn, and why it matters
They first proposed gating on the analysis token instead: running an analysis is real work already done, so the token is decent evidence somebody meant it. Sound for abuse resistance, wrong for this requirement — which is about consent, not cost.
A token proves an analysis happened. It does not prove a person is present, nor that the person present is the one who ran it. Analysis tokens travel in URLs that people paste into tickets and papers, so token-as-authorization lets a forwarded link send someone else's identifier list to a model provider.
The sharper point is second-order: FR-011 and FR-012 make summarising opt-in with a choice of disclosure tier. A choice a bot holding a link can make is a consent mechanism that consents on the user's behalf — worse than offering no choice, because it looks like one.
Tasks
T031 done. T031a (the 30-minute bound), T031b (limiter keyed on
subject, plus a per-token limit) and T031c (a stalehuman_iatrefused with zero model calls) are the work it implies. T031c exists because the freshness half is the one most likely to be dropped: the claim being present looks like success.One external dependency remains and it is theirs — their proxy mints caller tokens for the answer route only, so a summary route must exist before any claim can be carried. Everything in Phase 8 can be built and tested first.
Documentation only; no code changes.
🤖 Generated with Claude Code