NotASithLord / NotASithLord/peerd
Contributor Metrics 3/3: exact-origin upload, browser consent, and preview rollout
Nobody has claimed this yet.
- Dominant language
- JavaScript
- Stars
- 410
- Forks
- 45
- Avg merge
- 11d 5h
- Merged PRs (30d)
- 1
Description
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 #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 #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.jsonandchannel-config.jsremain 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.mdREADME.mdSECURITY.mddocs/security/THREAT-MODEL.mddocs/security/RED-TEAM-RESULTS.mddocs/store/PRIVACY.mddocs/store/LISTING.mddocs/store/REVIEWER-NOTES.mddocs/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 #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.
- #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.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Begin with the #345 canonical-byte and #346 collector contracts, then inspect the peerd-egress entry point and generated manifest.json and channel-config.js paths. Run the listed pure/client and in-browser tests first, followed by packaging and live E2E verification. Done means preview/dev works with consent while store Chrome, Firefox, and web artifacts contain no collector or uploader traces.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript
- Domain
- documentation, release, security, testing
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 25/100