Option 2: the Worker forwards, Chirp enforces

The Worker still owns everything Phosra — Gatekeeper, the Link ceremony, signed receipts, profile refresh. Chirp's origin is locked so only the Worker can reach it, which lets Chirp trust one header from the Worker and filter in its own database queries. Screenshots from npm run demo:edge-header; the parent's Link flow is identical to option 1.

1 · One request, end to end

Maya opens her Chirp home feed. The parent linked her profile through Phosra Link, so the Worker holds an applied content-rating ceiling of 13 for it.

  1. Worker deletes any Phosra-Content-Rating-Max or X-Origin-Auth the browser sent.
  2. Worker asks Chirp who is signed in, finds Maya's applied ceiling, and adds Phosra-Content-Rating-Max: 13 plus its origin secret.
  3. Chirp rejects anything without the origin secret, then runs WHERE rating <= 13.
  4. Chirp answers with Phosra-Content-Rating-Applied: 13.
  5. Worker passes acknowledged responses through; filters any listed response that is not acknowledged.

Everything Chirp adds is one small module and a few lines where it already builds its timeline:

// chirp/src/edge-policy.ts (26 lines) — trust the Worker, read its policy
if (!fromTrustedEdge(request, EDGE_ORIGIN_TOKEN)) return 403       // origin is locked
const ceiling = edgeCeiling(request)                           // Phosra-Content-Rating-Max
const posts = await store.timeline({ maxRating: ceiling })   // WHERE rating <= ceiling
response.headers.set("Phosra-Content-Rating-Applied", String(ceiling))

2 · The rule, enforced by Chirp

Same outcome as option 1 — 8 posts for Maya, 12 for Dana — but the filtering happened in Chirp's query, and the notice is Chirp's own UI. The Worker did not touch the page.

Maya8 postsratings 0 · 7 · 13
Dana (parent)12 postsno header sent, nothing filtered
Enforced byChirpx-phosra-edge: …; enforced-by=origin
O2·1Maya, through the Worker Chirp enforcesNotice: “Policy delivered by Chirp's edge Worker; applied by Chirp.” Every 16+ and 18+ post is gone.
O2·2Dana, unrestricted ChirpNo link for the parent's profile, so the Worker sends no policy header.
O2·3The JSON feed and its headers Worker ↔ ChirpChirp acknowledged 13, so the Worker passed the response through: enforced-by=origin. Mobile and API clients get the same filtering, with nothing listed in the Worker config.

3 · The origin only answers the Worker

This is what makes the header trustworthy. Here the Worker sends a secret X-Origin-Auth; in production use a Cloudflare Tunnel (no public origin address), Authenticated Origin Pulls (mTLS), or Cloudflare Access with a service token.

O2·4Maya's session, straight to the origin :4011 origin403 · Origin locked for pages and for /api/timeline, even with a forged policy header. Compare option 1, where the open origin served all 12 posts.

4 · A child can't loosen the policy

Maya opens her browser's dev tools and sends Phosra-Content-Rating-Max: 99 and a guessed X-Origin-Auth through the public address.

O2·5Spoofed headers are dropped WorkerThe Worker deletes both before adding its own. Highest rating returned: 13.

5 · If Chirp stops enforcing, the Worker still does

To test this, the origin was swapped for a Chirp build that ignores the header — as if a deploy dropped the enforcement code. With no Phosra-Content-Rating-Applied on the response, the Worker filters listed pages and feeds itself (enforced-by=edge-fallback).

O2·6Unacknowledged response, filtered at the edge Worker fallbackStill 8 posts. The notice says Chirp did not confirm the policy, so the Worker filtered the page.

6 · The three ways to deploy

Every option uses the same parent flow, the same Gatekeeper and the same signed receipts. They differ in where Phosra runs and who filters content.

NativeOption 1 · Worker enforcesOption 2 · Worker forwards, Chirp enforces
Phosra SDK, tables, secret, background jobsIn ChirpIn the WorkerIn the Worker
Chirp code for Phosra~230 lines + worker processNone (session endpoint + data-rating)~40 lines: trust check, read header, acknowledge
Who filters contentChirp's queryWorker rewrites HTML / JSONChirp's query; Worker as backstop
Endpoints coveredAllOnly those listed in Worker configAll (listed ones also backstopped)
Depends on page markupNoYes (selectors)No (only for the backstop)
Origin must be lockedNoYes, or it can be bypassedYes, required to trust the header
Gatekeeper upgradesChirp redeployWorker deployWorker deploy
New rule categoryChirp codeWorker code + selectorsWorker header + Chirp code
Run itnpm run demo:nativenpm run demo:edgenpm run demo:edge-header