You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The ingress a person uses to add a Source this project does not run: paste a Provider's URL, and the application reads its capability declaration and speaks the published contract to it from then on.
Decision 7 is the decision, and it is unambiguous about the band. CAN-96 Record the architecture decisions of 15 August, and make the repository agree says: "Users may paste third-party provider URLs in v1, and the duties are accepted." ADR-0014 Decision 2 keeps it — "a pasted URL pointing at a stranger's service is still supported" — and records the paste-a-URL shape as one of the parts of ADR-0007 that survives unchanged.
This ticket exists because nothing built it. Decision 7 put the capability in v1 on 15 August 2026 and no ticket carried it; CAN-100 Restructure the tracker for the architecture change found the gap while auditing its own work. Decision 4's reasoning depends on this being real — CAN-7 Provider contract: define and publish it moved into v1 "because decision 7 means third-party implementors exist from the start", so a contract published for implementors who cannot be reached would be publishing into nowhere.
Listed is the boundary, and it has to be visible
CONTEXT.md defines a Listed Provider as one "this project writes and runs, named in the product's own list rather than pasted in by a person. Anything off that list is a stranger's service however familiar the Source behind it looks."
A pasted Provider is not Listed, and the interface must not let the two blur. ADR-0014 rejects a community registry outright, so there is no review step to hide behind: the person pasting is accepting a stranger's service, and the product's job is to make that legible rather than to vouch for it. A pasted provider-tmdb lookalike is still a stranger's service.
What it must carry
Fetching a user-supplied URL server to server is the exposure. The application will make requests to an address a person chose, which is a server-side request forgery vector: internal addresses, link-local metadata endpoints, redirects into private ranges, and DNS that resolves differently on the second lookup. Treat the fetch as hostile input — allowlist scheme and port, refuse private and link-local ranges, re-check after every redirect, cap size and time.
Everything the application honours arrives from a party it does not control. CAN-104 Read a Provider's capability declaration, and refuse what it does not serve already says absence is refusal rather than permission; this is where that bites hardest, because a stranger's declaration is the only thing standing between a pasted URL and displayed content. In particular a pasted Provider declaring no content classification must not have artwork displayed, per ADR-0012.
A signed-in person can add a Provider by pasting its URL, and the application reads its capability declaration and registers it as a Source for that person.
The fetch is hardened against server-side request forgery: scheme and port allowlisted, private and link-local ranges refused, redirects re-checked, response size and time capped.
A URL that does not answer the contract, or answers a version the application does not speak, is refused with a reason the person can act on.
A pasted Provider is visibly distinguished from a Listed one wherever its values are displayed, and the product never presents it as vouched for.
A pasted Provider's prose adds its own case to apps/web/src/app/no-linkification.test.tsx: a URL arriving from the pasted Provider renders as text and produces no anchor element. The prohibition behind it is origin-blind and enforced by lint (react/no-danger, plus a restricted-import group that is a name-matching tripwire rather than a proof, both in apps/web/eslint.config.mjs), added by CAN-108 Re-assess the illegal-content risk before a user can paste an arbitrary Provider URL, so what this ticket owes is the assertion at its own surface rather than the rule.
A person can remove a pasted Provider, and removing it does the right thing to the Snapshots it sourced rather than orphaning them.
CONTEXT.md gains the term for a pasted, unlisted Provider, since it currently defines only the Listed case.
Pasted Providers are not moderated, and that is now decided rather than assumed. They are never reviewed, listed, allowlisted or vouched for; what is moderated is their content, under ICU C1 and C2 like any other. An operator blocklist of Provider URLs was considered and rejected, and is recorded as the first thing to build if the reassessment triggers fire. The reasoning is in docs/compliance/illegal-content-risk-assessment.md under Pasted Providers are not moderated; their content is.
Two constraints the redone assessments now impose on this build. Import stays a record at a time, chosen by its owner — bulk or scheduled import from a pasted Provider is a change requiring both assessments to be redone again, because it is what strains the reviewable-corpus control that holds finding 2c at low. And a pasted Provider declaring no content classification has no artwork displayed from it at all, which the children's risk assessment now carries as well as this ticket.
Parent
CAN-17 v1: the walking skeleton in production, then the founding case
What to build
The ingress a person uses to add a Source this project does not run: paste a Provider's URL, and the
application reads its capability declaration and speaks the published contract to it from then on.
Decision 7 is the decision, and it is unambiguous about the band.
CAN-96 Record the architecture decisions of 15 August, and make the repository agree
says: "Users may paste third-party provider URLs in v1, and the duties are accepted."
ADR-0014 Decision 2 keeps it — "a pasted URL
pointing at a stranger's service is still supported" — and records the paste-a-URL shape as one of
the parts of ADR-0007 that survives unchanged.
This ticket exists because nothing built it. Decision 7 put the capability in v1 on 15 August
2026 and no ticket carried it; CAN-100 Restructure the tracker for the architecture change
found the gap while auditing its own work. Decision 4's reasoning depends on this being real —
CAN-7 Provider contract: define and publish it moved into
v1"because decision 7 meansthird-party implementors exist from the start", so a contract published for implementors who cannot
be reached would be publishing into nowhere.
Listed is the boundary, and it has to be visible
CONTEXT.mddefines a Listed Provider as one "this project writes and runs, named in theproduct's own list rather than pasted in by a person. Anything off that list is a stranger's service
however familiar the Source behind it looks."
A pasted Provider is not Listed, and the interface must not let the two blur. ADR-0014 rejects a
community registry outright, so there is no review step to hide behind: the person pasting is
accepting a stranger's service, and the product's job is to make that legible rather than to vouch
for it. A pasted
provider-tmdblookalike is still a stranger's service.What it must carry
Fetching a user-supplied URL server to server is the exposure. The application will make requests
to an address a person chose, which is a server-side request forgery vector: internal addresses,
link-local metadata endpoints, redirects into private ranges, and DNS that resolves differently on
the second lookup. Treat the fetch as hostile input — allowlist scheme and port, refuse private and
link-local ranges, re-check after every redirect, cap size and time.
Everything the application honours arrives from a party it does not control.
CAN-104 Read a Provider's capability declaration, and refuse what it does not serve
already says absence is refusal rather than permission; this is where that bites hardest, because a
stranger's declaration is the only thing standing between a pasted URL and displayed content. In
particular a pasted Provider declaring no content classification must not have artwork displayed,
per ADR-0012.
Its declared retention is trusted for a compliance decision. ADR-0014 records that consequence as
forced by Decision 1 rather than argued away, and it is sharper here than for a Provider we run:
CAN-102 Give Source a retention policy, and Snapshot a fetched-at stores what the
stranger claims, and CAN-103 Refresh Snapshots before their Source's retention expires, and drop what cannot be refreshed
acts on it.
Its attribution obligation is its own, carried by
CAN-105 Carry each Source's attribution obligation through to every surface that displays it
and attributed per field by
CAN-110 Carry per-field provenance to every displayed value.
Acceptance criteria
apps/web/src/app/no-linkification.test.tsx: a URL arriving from the pasted Provider renders as text and produces no anchor element. The prohibition behind it is origin-blind and enforced by lint (react/no-danger, plus a restricted-import group that is a name-matching tripwire rather than a proof, both inapps/web/eslint.config.mjs), added by CAN-108 Re-assess the illegal-content risk before a user can paste an arbitrary Provider URL, so what this ticket owes is the assertion at its own surface rather than the rule.CONTEXT.mdgains the term for a pasted, unlisted Provider, since it currently defines only the Listed case.s.9(4)ands.11(4), not a documentation step.Blocked by
Amended 17 August 2026
CAN-108 Re-assess the illegal-content risk before a user can paste an arbitrary Provider URL is the ticket that redoes both statutory risk assessments, and three things above change when it merges.
The shipping gate opens when CAN-108 Re-assess the illegal-content risk before a user can paste an arbitrary Provider URL merges, and not before. Both statutory assessments are redone under
s.9(4)ands.11(4), dated 17 August 2026 — but on the CAN-108 Re-assess the illegal-content risk before a user can paste an arbitrary Provider URL branch. Until that lands onmainthe condition the last criterion names is unmet, and this ticket must not be started. The criterion stays on the list afterwards as the record of why.Pasted Providers are not moderated, and that is now decided rather than assumed. They are never reviewed, listed, allowlisted or vouched for; what is moderated is their content, under ICU C1 and C2 like any other. An operator blocklist of Provider URLs was considered and rejected, and is recorded as the first thing to build if the reassessment triggers fire. The reasoning is in
docs/compliance/illegal-content-risk-assessment.mdunder Pasted Providers are not moderated; their content is.Two constraints the redone assessments now impose on this build. Import stays a record at a time, chosen by its owner — bulk or scheduled import from a pasted Provider is a change requiring both assessments to be redone again, because it is what strains the reviewable-corpus control that holds finding 2c at low. And a pasted Provider declaring no content classification has no artwork displayed from it at all, which the children's risk assessment now carries as well as this ticket.