Repository navigation
Conversation
* feat(extension): onboarding consent screen for the opt-in On a first install the extension opens a short consent page (vi, en, cs): what the lookup sends, what the opt-in would add (the same field list as the side panel), that nothing more is sent until the user says yes, and that the side panel can change it. "No" has the focus and the primary style; closing the page keeps the default, off. The choice goes through RATE_UPDATE_SETTINGS to the same setting as the side panel toggle, which now follows changes made elsewhere. The sender guard accepts a tab sender only when it is this extension's consent page URL, exactly; content scripts stay refused. Updates and reloads do not open the page. Refs #1603, #1175 * fix(extension): consent page sets only the opt-in, defaults first - isOnboardingSender accepts the exact consent page URL and lets it set the opt-in alone; isPrivilegedExtensionSender refuses tab senders again. - onInstalled writes each missing default before opening the page, so a quick choice is never overwritten; a stored choice is kept. - The page status follows the stored choice. Refs #1603 * fix(extension): consent copy, choice state and docs after review - The consent page has its own opt-in text (onboardingOptInBody): the same fields as the side panel, tested, plus the server re-check and "no account, name, email or cookies". The lookup line lists every field lookup sends. - "Off by default" and how to reach the side panel toggle replace the vague line; vi, en and cs say the same. - Keyboard focus stays on the clicked button, the status is announced again on a repeat, and aria-pressed marks the stored choice. - The privacy policy and CHROMEWEBSTORE.md name the consent page; RELEASE.md has a test step and changelog line for it. Refs #1603 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…gateway (#1607) * feat(importer): review ai points job calls models through the dos.ai gateway JOY decided on 2026-11-04 that the job uses dos.ai, not the Anthropic API (D2 of the AI review points design). The job now sends its batch through the gateway's OpenAI-compatible Files and Batch API with DOS_AI_API_KEY (DOS_AI_BASE_URL overrides the URL). That Batch API serves dos, qwen3.8 and deepseek models only, so the default model is dos (Qwen3.8 27B on DOS GPUs) and qwen3.8-max is the fallback, with the same monthly caps. Caps, kill switch, process-once, evidence checks and quality stops are unchanged. A cut-off or filtered answer (finish_reason length or content_filter) and an errored line are stored as failed. Cached tokens count at the full input price, an upper bound. @anthropic-ai/sdk is removed. The proposal notes the D2 change. Refs #1531 * fix(importer): dos.ai batch client never creates a batch twice Review findings on the dos.ai client (#1531): - POST /batches is retried only on 429; a lost answer throws and says a batch may exist, instead of creating and billing a second one. - A batch failed as a whole, one with no output, or one whose output file is gone (404) closes its row and stores nothing, so its reviews are due again without spending an attempt; a line not run for want of credits is unbilled, not failed. - Each call's timeout covers reading the body. - Tests: create-once on a network error and a 502, retry on 429, failed and purged batches, 402 lines, the request body; batch ids renamed. - The proposal notes the dos.ai batch path in sections 4 and 5. Refs #1531 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… ingest (#1609) * feat(extension,web): extension observation v1, stock and sku, flagged ingest - shared-data: ExtensionObservation v1 in rules, plain functions with no zod. The parser names the first broken field the way the DOS-Me RPC does in DETAIL. No ratings, all keys required, listing host must match the marketplace, and observed_at must be within the last 24 hours (up to 10 minutes ahead). - Extension: the extractor reads stock state and quantity (JSON-LD availability and inventoryLevel, product meta) and the SKU (Lazada and Tiki URLs, JSON-LD sku). buildExtensionObservationV1 maps a signal to v1. Nothing new is sent: the lookup and the opt-in payload are unchanged, and a test pins that. - Web: POST and DELETE /api/v1/rate/extension/submitter and POST /api/v1/rate/extension/observation call the narrow M2 RPCs as anon. They answer 404 NOT_ENABLED unless RATE_EXTENSION_OBSERVATIONS=1, and observations also need RATE_NETWORK_HASH_SALT. Only an HMAC of the /24 or /48 reaches the database, never the raw IP. Refs #1606, #1175 * fix(extension,web): m2 review fixes, ingest key and variant-true stock Web: - The RPCs now take RATE_EXTENSION_INGEST_KEY (checked by sha256 in the database), so nobody can call them around these routes with the anon key. Writes need the key and the salt, else 503 before the database. - Register sends the network hash too. An address with no range hashes to one shared "unknown" bucket instead of skipping the limit. IPv4-mapped IPv6 maps to its /24. - Web page origins are refused (403); CORS goes only to extension origins; bodies must be application/json (415). OPTIONS is 404 while off. RPC refusals log their code; 54000 answers Retry-After 3600; 42501 is a 503. Shared rules: listing_url and observed_at follow the RPC exactly (raw https prefix, lowercase host, no port, user, ';' or space; ISO 8601 with a zone, offsets as the RPC takes them); lengths count code points; unpaired surrogates are refused. Extension: - Stock and SKU come from the selected variant's own offer: the only offer, or the one whose sku or name matches the selected variant; never another variant's or the parent's when several exist. The meta fallback reads head meta only. - Availability: schema: prefixes, arrays, Reserved and pre-order forms. A quantity is kept only when it agrees with the state. - extractorSource follows price, list price and stock. A long variant label is cut to 120 for v1. skuId uses the external id sanitizer. - buildLookupParams carries the lookup query; tests pin the exact lookup query and opt-in payload, and cover a page end to end. Refs #1606 * fix(web): observed_at bounds match postgres, brake retry-after - observed_at refuses seconds of 60 and offsets beyond +-15:59, which Postgres refuses, so the validator and the RPC agree. - A 54000 from the global register brake answers Retry-After 60; the hourly limits keep 3600. Refs #1606 * fix(shared-data,web): host check without a built regex, test key at run time - isExtensionMarketplaceHost checks subdomains by suffix and a fixed label pattern instead of a RegExp built from the host table (CodeQL incomplete escaping). - The ingest key test value is built at run time; the already-pushed fixture line in d19083a gets a .gitleaksignore fingerprint. Refs #1606 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* docs(proposals): dos-me extension observation quarantine (m2) Draft DOS-Me migration for ExtensionObservation v1 (#1606). Nothing is applied. - rate.extension_submitters and rate.extension_observations, RLS on, no anon or authenticated table access, rate_worker reads and updates status only. - register, submit, delete and purge RPCs, security definer with an empty search_path, with the contract's SQLSTATEs and DETAILs, limits and 28/180 day retention. - Verify and rollback files, and a Docker replay that exercises every RPC, the grants, the rollback and a re-apply. Refs #1606 * docs(proposals): extension observations revision 2, ingest key and limits Applies Revision 2 of the M2 contract (#1606). Nothing is applied. - rate.extension_ingest_secret: register and submit check the sha256 of an ingest key (42501, DETAIL ingest_key); the network hash is required in both. - Register: 20 an hour per network hash, then the global brake under an advisory lock; submitters keep their network hash. - Purge: empty submitters after 7 days, locked first and deleted under a fresh check. - DETAIL observation for an unknown key; presence checked per field in the validator order; semicolons and JavaScript spaces refused in listing_url. - Verify: owner, no forced RLS, column list, limits in the bodies, no grants on the key. - Replay: parity with parseExtensionObservationV1, exact thresholds, ingest key, the purge race; wired into CI after the shared-data build. Refs #1606 * fix(proposals): extension observations purge lock order and key checks Re-review fixes for the M2 quarantine proposal (#1606). Nothing is applied. - Purge clears submitter hashes before observation hashes, the lock order of delete, so a delete during a purge waits instead of deadlocking. The replay stalls a purge, runs a delete in the middle, and fails with the old order. - The key row cannot hold the sha256 of the empty string, and register and submit refuse a missing key or one under 32 characters (42501, DETAIL ingest_key). - observed_at: seconds 00 to 59 and offsets up to 15:59, as Postgres parses them. - The .md runbook is written for the applying session: CSPRNG key, printf hash, Vercel secrets, apply, row, verify, then the flag; rotation is a hard cut. Refs #1606 * Merge remote-tracking branch 'origin/dev' into docs/1606-dos-me-extension-observations Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…res (#1610) * feat(extension): opted-in installs send observation v1, with disclosures 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 * fix(extension): observation client with kept erasure, holds and consent 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>
…#1611) * chore(db): mirror the m2 extension observation migrations from dos-me DOS/DOS.Me#1560 (quarantine and key row), #1564 (daily purge schedule) and #1569 (key row rotation) carry #1606. The quarantine and the purge schedule are on production through #1561 and #1568; #1569 is merged on dev. Mirror the four migrations byte for byte into supabase/migrations and regenerate packages/shared-data/src/database.types.ts: the three extension tables and the register, submit, delete and purge functions. The extension observations proposal replay now rolls the mirrored quarantine back first, so it still replays from the stack before it. Nothing is applied by this change. Refs #1606 * chore(db): follow the ingest key rotation to version 20261109090000 DOS/DOS.Me#1578 moves the rotation off 20261107100000, which two other DOS.Me migrations also used. Mirror the renamed file byte for byte. Refs #1606 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
* chore(db): mirror the four older drift migrations from dos-me DOS/DOS.Me is the only deployable ledger. Four rate migrations differed between it and supabase/migrations: - 20261013192302_jreviews_rating_and_review_flags.sql and 20261014011054_review_votes.sql: the DOS.Me version is the one on production (no explanatory comments; review_flags policies created only when missing). Replace the reference copies with it. - 20261025090000_rate_product_images_bucket.sql: only in DOS.Me. It needs the Supabase storage schema, so the replay skips it, as DOS.Me's own replay does (NOT_REPLAYED in scripts/lib/rate-db.mjs). - 20261106150000_rate_listing_price_context_peer_max_history_first.sql: only in DOS.Me (Rate-Services price context). Mirrored, and database.types.ts regenerated: history_first_at and peer_reference_max. Nothing is applied by this change. Refs #1606 Co-Authored-By: Claude Sonnet 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.
|
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the
|
There was a problem hiding this comment.
⏱️ Code Review completed (50 eligible files · 382,866 chars · 3 model call(s) · 13 PR unit(s))
Whole diff with bounded context at base 8919776 / head 1ba7325.
Excluded by noise policy: pnpm-lock.yaml.
✅ CLEAN_PASS: Complete diff reviewed
Context investigation was bounded to the explicitly requested snapshot paths.
🔒 Dependency check
✅ Passed. Every new package version comes from the public registry or a source this lockfile already used for it, its checksum is pinned where the format records one, and OSV lists no new malicious package or high or critical vulnerability for the versions it was asked about.
Promote dev to main.
Merge with a merge commit, never squash (Docs/Resources/RELEASE.md).
📌 TL;DR
This PR introduces the M2 database migration and documentation for the "extension observation quarantine," establishing a secure, rate-limited ingestion pipeline for browser extension data with strict privacy controls. It also updates the AI review proposal to reflect a pivot from Anthropic Claude to the internal
dos.aiBatch API.🎯 Type of Change
🔍 Changes Walkthrough
.github/workflows/ci.yml.gitignore.gitleaksignorewrite-paths.test.ts.Docs/Proposals/2026-11-03-ai-review-points.htmldos.ai(Qwen/DeepSeek models) via the Batch API, including new cost estimates and API key changes.Docs/Proposals/2026-11-04-dos-me-extension-observations.mdDocs/Proposals/2026-11-04-dos-me-extension-observations.sqlextension_ingest_secret,extension_submitters, andextension_observationstables. Defines strict RLS policies, column-level grants, and fourSECURITY DEFINERfunctions for registration, submission, deletion, and purging.Docs/Proposals/2026-11-04-dos-me-extension-observations-verify.sqlDocs/Proposals/2026-11-04-dos-me-extension-observations-rollback.sql📊 Architectural Flow
sequenceDiagram participant Ext as Browser Extension participant Web as Web API (Vercel) participant DB as PostgreSQL (Supabase) participant Cron as Daily Purge Job Note over Ext,Web: Ingest Key & Network Hash Validation Ext->>Web: POST /api/extension/submit (Key, Observation, NetHash) Web->>Web: Validate Payload (Shared Validator) Web->>DB: RPC: rate.submit_extension_observation() alt Key Invalid or Rate Limit Exceeded DB-->>Web: Error (42501 or 54000) Web-->>Ext: 401 or 429 else Valid DB->>DB: Insert into rate.extension_observations (Status: quarantined) DB-->>Web: {id, status, received_at} Web-->>Ext: 200 OK end Note over Cron,DB: Privacy & Retention (Daily) Cron->>DB: RPC: rate.purge_extension_observations() DB->>DB: Clear network_hash (>28 days) DB->>DB: Delete observations (>180 days) DB->>DB: Delete empty submitters (>7 days)