Repository navigation
feat(extension): opted-in installs send observation v1, with disclosures - #1610
Conversation
The opt-in now sends ExtensionObservation v1 to the observation route with a random submitter id from the submitter route, instead of the legacy crowd ingest (no title, no ratings). Turning the opt-in off deletes the id and every observation sent with it. The web routes stay off (RATE_EXTENSION_OBSERVATIONS), so nothing is stored until JOY turns them on. The opt-in text, the consent page, the privacy policy (vi, en, cs), CHROMEWEBSTORE.md and the changelog name the v1 fields, the submitter id and the salted network-range hash with its retention; a test ties the texts to the v1 keys. Refs #1606 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nt v2 - observation-client.ts runs register, send and erase on one chain: two product pages register one id, and an opt-out waits for a send in flight; an id issued after the opt-out is erased at once. - Erasures stay queued until the server confirms (200) and are retried at start-up and on the next send; the stored id carries the server that issued it, and an id from another server is erased there. - 429 holds for its Retry-After; routes off (404 NOT_ENABLED) or 503 hold an hour, so opted-in installs stop asking. - An opt-in given to the older crowd signal is not consent to v1: it reads as off, and an update reopens the consent page. - Disclosures: stock quantity, the server-derived network hash, the IP sentence, one name for the contributor ID, the uninstall case, and a release test step for erasure. - Behavioural tests for the client with stubbed storage and fetch. Refs #1606 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
If your organization's extra usage balance is empty, an organization admin can add extra usage credits at claude.ai/admin-settings/usage. If its monthly spend limit was reached, an admin can raise it on the same page. If neither applies, contact Anthropic support.
Once extra usage is available, someone with write access to this repository can comment @claude review on this pull request to trigger a review.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Caution Review failedThe pull request is closed. Walkthrough
Merge Risk:
|
Refs #1606
Refs #1175
This is step 4 of JOY's "Duyệt M2" (2026-11-04): opted-in installs switch to ExtensionObservation v1, and every disclosure is updated. The web flag
RATE_EXTENSION_OBSERVATIONSstays off, so the observation routes answer 404 and nothing is stored until JOY turns them on. Nothing is published to a store.What changes
The opt-in sends v1. It now goes to
POST /api/v1/rate/extension/observation, instead of the legacy crowd ingest.POST /api/v1/rate/extension/submitter.observation-client.tsruns register, send and erase on one chain:Turning the opt-in off erases.
DELETE /api/v1/rate/extension/submitterdeletes the id and every observation sent with it.Consent version 2. An opt-in given to the older crowd signal is not consent to v1. It reads as off, and an update reopens the consent page.
Disclosures, tied to the v1 keys by a test:
CHROMEWEBSTORE.md;RELEASE.mdchangelog and a test step for erasure.They name every field, the contributor id, the network-range hash and its retention (28 days for the hash, 180 for observations), erasure on opt-out, and the uninstall case. The IP sentence now says the hash is derived from the IP and the IP itself is never stored.
Tests
pnpm test,tsc,eslintandpnpm buildpass inapps/extension.New behavioural tests drive the client with stubbed storage and fetch:
Review
Two fresh-context Claude reviews were run on 1625f16: privacy and consent, and the worker logic against the server contract. Neither blocks while the flag is off. Fixed in 254f608:
Left as is:
buildCrowdIngestPayloadstays exported for the web ingest route's tests. The extension no longer calls it, and esbuild drops it.Codex not run.
🤖 Generated with Claude Code
📌 TL;DR
This PR replaces the legacy "crowd signal" opt-in with a new ExtensionObservation v1 system that sends minimal, pseudonymous product data (price, stock, SKU) instead of ratings. It introduces a robust
ObservationClientto manage a random submitter ID, handles strict data erasure (GDPR-style) when users opt out, and updates all privacy disclosures and localization files to reflect the new data retention and hashing policies.🎯 Type of Change
🔍 Changes Walkthrough
apps/extension/CHROMEWEBSTORE.mdapps/extension/RELEASE.mdapps/extension/src/_locales/{cs,en,vi}/messages.jsonoptInBodyandonboardingOptInBodystrings to list the new fields (SKU, stock, timestamp, submitter ID) and explicitly state that ratings are no longer sent. Added new keys for observation field labels.apps/extension/src/background/observation-client.tsObservationClientclass. Handles:1. Registering a random submitter ID.
2. Sending observations with the ID.
3. Managing a "pending erasure" queue to ensure data is deleted from the server when the user opts out (retrying on failure).
4. Handling rate limits (429) and service unavailability (503/404).
apps/extension/src/background/service-worker.tsObservationClient.1. Replaced
buildCrowdIngestPayloadwithbuildExtensionObservationV1.2. Added consent versioning (
OPT_IN_CONSENT_VERSION = 2) to force re-consent for users who opted in to the old system.3. Triggered
observationClient.forget()when the user toggles the opt-in off.4. Added
onStartuplistener to retry pending erasures.apps/extension/src/security-guards.tsbuildExtensionObservationV1documentation. AddedOBSERVATION_FIELD_LABELSandOBSERVATION_EXTRA_LABELSconstants to map observation fields to i18n keys for testing and disclosure verification.apps/extension/src/test-extension-pipeline.ts1. The new observation payload structure.
2. That all i18n locales disclose the new fields.
3. That the
ObservationClientcorrectly registers, sends, and erases data (including retry logic and concurrent request handling).apps/extension/src/types.tschrome.runtime.onStartupandchrome.storage.local.removeto support the new client logic.apps/web/locales/{cs,en,vi}.jsonprivacyS5Desc) to accurately describe the new extension data collection, hashing, and erasure mechanisms.📊 Architectural Flow
sequenceDiagram participant User participant Extension as Extension (Service Worker) participant Client as ObservationClient participant Storage as Chrome Storage participant Server as Rate.vn API Note over User, Extension: User views product page (Opt-in ON) User->>Extension: View Product Extension->>Client: send(apiBaseUrl, observation) Client->>Storage: Check pending erasures alt Pending Erasures Exist Client->>Server: DELETE /submitter (retry) Server-->>Client: 200 OK Client->>Storage: Clear pending erasures end Client->>Storage: Get Submitter ID alt No ID Found Client->>Server: POST /submitter (Register) Server-->>Client: 200 OK (submitterId) Client->>Storage: Save Submitter ID end Client->>Server: POST /observation (with ID) Server-->>Client: 200 OK (Quarantined) Note over User, Extension: User turns Opt-in OFF User->>Extension: Toggle Opt-in OFF Extension->>Client: forget() Client->>Storage: Get Submitter ID Client->>Storage: Remove Submitter ID Client->>Storage: Queue Erasure (ID) Client->>Server: DELETE /submitter Server-->>Client: 200 OK Client->>Storage: Clear Pending ErasuresSummary by CodeRabbit