Skip to content

Contributor Metrics 3/3: exact-origin upload, browser consent, and preview rollout #347

Description

@NotASithLord

Parent: #344
Depends on #345 and the deployed/staged collector contract from #346.

Outcome

Connect the opt-in local Contributor Metrics envelope to the aggregate-only collector and roll it out to preview/dev only.

This issue owns:

  • A dedicated exact-origin contribution egress client.
  • Sealed batch lifecycle, retry/deduplication, scheduling, manual send, and local audit.
  • Firefox built-in data-collection consent integration and a compatible older-runtime path.
  • Chrome prominent disclosure/consent and all product/store/privacy documentation.
  • Preview/dev packaging and live end-to-end verification.
  • A hard proof that store artifacts still contain no collector origin or active contribution path.

Completing this issue does not authorize store telemetry. Store enablement requires a separate owner go/no-go issue after preview evidence and policy review.

Egress architecture

Dedicated client

Add one narrow contribution client in peerd-egress; do not add the collector to provider safeFetch and do not route contributions through open-web webFetch.

Required behavior:

  • One generated/configured exact HTTPS origin and one versioned POST path.
  • POST only.
  • credentials: 'omit'; no cookies, Authorization, API key, DPoP proof, session credentials, Referer, user-provided headers, or browser-derived metadata under application control.
  • redirect: 'error'; any redirect is a failed upload.
  • Fixed content type and schema version.
  • Named body and response caps.
  • Short wall-clock timeout and AbortSignal support.
  • Response parser accepts only Contributor Metrics 2/3: aggregate-only collector and operations boundary #346's fixed receipt and ignores no extra values: unknown keys fail closed.
  • No response value can mutate runtime settings, prompts, feature flags, experiment arms, schedules, or model behavior.
  • Every attempt/success/failure is written to the local audit log using counts/status only—never the envelope body, batch id, or rejected server text.
  • The model/tool/actor descriptor inventory exposes no contribution tool.

The host shell injects network IO. The pure client contract stays independently Bun-testable.

Sealed batch lifecycle

  • Snapshot the canonical bytes from Contributor Metrics 1/3: closed local schema, consent, preview, and feedback #345 and add a cryptographically random, single-batch idempotency token.
  • Freeze the bytes for preview/send/retry. A retry sends the identical envelope/token; live counters continue into a new pending aggregate.
  • On an accepted receipt, retire the sealed batch exactly once and preserve counts accumulated after sealing.
  • Concurrent alarm/manual sends share one in-flight operation.
  • Service-worker eviction/restart resumes a sealed pending batch without duplication.
  • A newer/unknown sealed-batch version fails read-only with a diagnostic.
  • Retry with bounded exponential backoff and jitter; no tight retry loops.
  • Queue/backlog and retention are bounded by named code constants.
  • Disable/revoke aborts the live request, cancels alarms, and clears pending/sealed batches and retry metadata.
  • Collector kill-switch/rejection never disables peerd or changes consent.

Scheduling and controls

Preview/dev participants receive:

  • An explicit Enable Contributor Metrics consent action.
  • A Send now action.
  • Automatic contribution no more frequently than the documented schedule, with randomized jitter.
  • Last attempted/accepted status in coarse human-readable form.
  • Exact pending/sealed payload bytes and collector origin visible in Settings.
  • Disable and clear that immediately stops/cancels the contribution path.

No onboarding modal on update that blocks normal use. A prominent, discoverable disclosure is required before enablement, but declining/ignoring it leaves full product behavior unchanged.

No collection or scheduling starts merely because a browser permission exists; both browser consent (where applicable) and peerd's current disclosure-version consent must be valid.

Browser and package consent

Firefox

Use Firefox's built-in data-collection permission system for technical/interaction data where available:

  • Declare only the optional category required by the v0 payload.
  • Request it from the direct user gesture that enables Contributor Metrics.
  • A denial/cancel leaves participation disabled and records no telemetry-specific data.
  • Revocation detected through the permissions API stops collection and clears pending state.
  • Implement the required compliant custom consent experience for supported older Firefox versions if they remain in the compatibility range; otherwise make any minimum-version change an explicit owner decision.
  • Generated Firefox manifests and AMO metadata must agree.

Reference:
https://extensionworkshop.com/documentation/develop/firefox-builtin-data-consent/

Chrome

Chrome requires a prominent in-product disclosure and affirmative informed consent for changed data practices. The disclosure cannot live only in the privacy policy or store listing.

  • Show data categories, purpose, collector, retention posture, forbidden-content list, revocation behavior, and a link to the published policy before Enable.
  • Update the Chrome Web Store privacy/data-use declarations and listing before publishing any artifact with an active upload path.
  • Treat an existing install upgrading from "no telemetry" as a changed-practice case; do not infer consent from use of preview/dev.

References:
https://developer.chrome.com/docs/webstore/program-policies/disclosure-requirements
https://developer.chrome.com/docs/webstore/user_data

Channel boundary

  • Preview/dev may include the endpoint and uploader after consent.
  • Store Chrome and store Firefox artifacts must contain no collector hostname/path, no contribution alarm/route, and no way to enable upload.
  • Generated manifest.json and channel-config.js remain generator-owned.
  • Add packaging/source invariants that fail CI if collector traces enter a store artifact.
  • The web build follows the store no-contribution posture unless separately decided.

Do not use a runtime channel probe. The generated channel configuration is the authority.

Documentation and trust-model update

Before preview rollout, update every live "no telemetry/no backend" statement so the repository and published materials are consistent.

At minimum audit and update as applicable:

  • AGENTS.md
  • README.md
  • SECURITY.md
  • docs/security/THREAT-MODEL.md
  • docs/security/RED-TEAM-RESULTS.md
  • docs/store/PRIVACY.md
  • docs/store/LISTING.md
  • docs/store/REVIEWER-NOTES.md
  • docs/store/PERMISSION-JUSTIFICATIONS.md
  • store data-use forms and the published peerd.ai privacy page
  • contributor/developer documentation for the schema and collector

The honest headline should be equivalent to:

No account, model proxy, content telemetry, or telemetry by default. People using preview/dev may explicitly opt in to content-free Contributor Metrics and inspect the exact aggregate payload before it is sent.

Do not keep an unqualified "no backend" claim once a collector exists. State that there is no required application/model backend and that the optional collector is a one-way aggregate sink.

Document:

  • Permitted and forbidden fields.
  • Transport/edge IP processing and application non-retention.
  • Aggregate and dedupe retention.
  • Lack of user-level deletion because no identity is collected.
  • How to revoke/clear pending data.
  • Why operational completion is not task success.
  • Why accepted data is observational and may be poisoned/noisy.
  • How schema/consent versions change.

Live measurement semantics

For the initial web-actor question, the contribution scorecard must distinguish:

  • Requested surface from resolved surface.
  • Runtime/manifest fallback reasons.
  • Page-code runs from discrete page action calls.
  • Actor turns, errors, cancellation, classified failure, duration, and token buckets.
  • Provider/catalog-known model cohort.
  • Binary "worked/didn't work" counts.

Do not compute or publish "task success rate" from clean completion alone. Report:

  • Operational completion rate.
  • User-reported worked rate where feedback exists.
  • Feedback coverage.
  • Efficiency/error measures.

Do not remotely assign code/tools arms. v0 observes the user's locally selected/configured surface and labels the result observational.

Tests and verification

Pure/client

  • Exact origin/path/method/headers/credentials/redirect/timeout contract.
  • Wrong origin/path/receipt/extra response field fails closed.
  • Abort and timeout stop the request.
  • Body and response caps are enforced.
  • No provider/open-web credentials can enter request construction.
  • Sealing/retry/acceptance/revocation reducer is deterministic.
  • Retry sends byte-identical payload and token.
  • Counts accrued after sealing survive acceptance.
  • Concurrent send admission produces one request.
  • Backoff, queue, retention, and newer-version behavior are bounded.

In-browser

  • Fresh/upgrade state is disabled and records/sends nothing.
  • Human enable gesture, disclosure version, Send now, status, preview, disable/clear.
  • Firefox grant/deny/revoke behavior using the real permissions seam.
  • Service-worker restart and alarm wake preserve exactly-once batch settlement.
  • Disabling during an in-flight request aborts it and clears state.
  • Agent, actor, page, hook, import, dweb, and forged messages cannot trigger/enable upload.
  • Binary feedback affects only aggregates and never the model transcript/context.
  • Local audit shows attempt/outcome without payload/batch identifiers.

Live E2E

Against a controlled staging collector:

  • Opt in → accumulate → inspect → seal/send → accepted aggregate.
  • Retry after dropped response deduplicates server-side.
  • Schema rejection preserves local batch for diagnosis without logging content.
  • Kill switch causes bounded failure and no product degradation.
  • Revoke before/during/after send has the documented behavior.
  • No cookie/redirect/remote-control response is accepted.

Packaging/store

  • Preview Chrome/Firefox include the declared optional path.
  • Store Chrome/Firefox and web build contain zero collector origin/path/uploader/alarm traces.
  • Firefox validator and Chrome/store preflight pass.
  • Generated-file drift, dweb boundary, packaged import graph, CodeQL/security scans, in-browser, E2E, and visual gates pass.
  • Published policy URL is live and byte/content-reviewed before release.

Adversarial review

Run independent reviews for:

  • Privacy/schema exfiltration and covert encoding.
  • Consent/version/revocation bypass.
  • SW concurrency, retry, duplicate/lost-count behavior.
  • Endpoint response as a remote-control channel.
  • Packaging/channel leakage.
  • Firefox/Chrome policy and disclosure accuracy.
  • Collector abuse/poisoning and logging/retention claims.

Acceptance criteria

  • Contribution egress is exact-origin, credentialless, redirect-free, bounded, audited, and isolated from provider/open-web fetches.
  • Preview/send/retry use identical canonical bytes.
  • Retry and SW restart cannot duplicate or lose a sealed batch.
  • Revocation aborts and clears all contribution state.
  • Browser permission plus current peerd consent is required; either missing means no collection/send.
  • Preview/dev rollout works end to end against Contributor Metrics 2/3: aggregate-only collector and operations boundary #346.
  • Store Chrome, store Firefox, and web artifacts contain zero collector/uploader traces.
  • Every no-telemetry/no-backend claim and store form is updated honestly before preview publication.
  • No raw debug artifact, content, arbitrary string, stable identity, or remote control path exists.
  • Live E2E, packaging, browser consent, security, and visual gates pass.
  • Adversarial reviews have no unresolved material findings.
  • Epic: opt-in Contributor Metrics without content telemetry #344 is updated with field evidence and an explicit recommendation; store enablement remains a separate decision.

Non-goals

  • Store telemetry enablement.
  • Remote experiment assignment/configuration.
  • Automatic debug bundle, OTel, audit, transcript, raw error, or crash upload.
  • Stable identity, accounts, user sync, DAU/retention funnels, or free-text feedback.
  • A general telemetry/event SDK.
  • Changing the model/provider data path.
  • Treating opt-in field metrics as randomized causal evidence.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    Status
    In progress

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions