AI that sees your screen, listens to your conversations and tells you what to do
| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
fix(cursor): point the MCP config at packages that exist Three of the four entries named packages never published to npm - @modelcontextprotocol/server-notion, -figma and -browser all 404 - and the fourth, -github, is deprecated upstream ("Package no longer supported"). Opening the repo in Cursor therefore failed on every entry. Notion, Figma and browser now point at the maintained servers, with the invocation each one documents: @notionhq/notion-mcp-server reads NOTION_TOKEN, figma-developer-mcp needs --stdio and reads FIGMA_API_KEY, and @playwright/mcp takes no credentials. GitHub's replacement is a Go/Docker server rather than an npx package, so that entry is dropped instead of pointed somewhere unverified. | 1 天前 | |
Update config.yaml to disable fun mode and adjust settings (#3505) | 9 个月前 | |
Establish a canonical subscription plan catalog (#11979) * docs: decide subscription plan authority and migration * feat: establish canonical subscription plan catalog * feat(plans): resolve free quota and chat exhaustion policy * fix(app): preserve unknown subscription plan ids * fix(macos): decode subscription plans losslessly * fix(macos): deny unknown plans paid capability * feat(web): decode subscription plans losslessly * fix(windows): decode subscription plans losslessly * feat: route desktop and phone policy through plan catalog * feat(plans): derive chat policy from catalog * fix(plans): make transcription limits explicit * feat(usage): attribute realized cost to catalog plans * docs(plans): mark the wire zero-sentinel as a deliberate W1-gated bridge The backend retired 0 == unlimited (catalog uses typed {kind: unlimited}, projected as None), but the wire has not been migrated: shipped clients still read 0 as unlimited. The None -> 0 coercion in the subscription response is therefore load-bearing, not a leftover. Annotate it so it is not 'fixed' out of sequence, and branch explicitly on None in the admin reset script where the same coercion would have folded a genuine finite 0 into unlimited. * test(plans): supply _effective_chat_limit to the trial-metadata synthetic namespace test_trial_metadata execs source text extracted from utils/subscription.py in a hand-built namespace. D3a routed get_trial_metadata and TRIAL_FEATURES through the new catalog helper _effective_chat_limit, which the namespace did not provide, so all 19 behavioral trial tests raised NameError. This is the failure mode of source-parsing tests that the design doc calls out when retiring TestStripeEntitlementMismatchScannerDrift: the test does not depend on behavior, it depends on the text of the function it copies. * fix(plans): make the catalog's new failure modes observable and pinned Findings from an independent glm-5.3 review pass, verified against the merge-base before acting: - payment.py: a retained-vs-configured price disagreement now raises where the pre-catalog code let the env mapping win. The bare 'except ValueError: return None' turned that into a silent stop to a paying subscriber's webhook writes. Emit record_fallback + a sanitized error so the Apr 17-20 failure shape is observable rather than log-only. - test_overage_catalog.py: pin chat-limit zero semantics. Base guarded on 'limit_value > 0', so 0 meant unlimited; per David's ruling 0 now means zero and denies. The tests call get_chat_quota_snapshot directly and were mutation-checked: restoring the old guard fails them. - users.py: name the inverse hazard for W1 -- 'or 0' also launders a finite zero into the unlimited sentinel. Latent today, silent capability grant if a plan ever declares a finite-zero allowance. - generate_plan_catalog.py: note that a None base catalog skips the append-only guard, which is correct only for the PR introducing the catalog. * chore(desktop): changelog fragment for the plan-catalog decoder work * test(plans): mirror the new fallback-telemetry names into the payment.py namespace Second instance in this PR of the same failure mode: test_stripe_webhook_behavioral execs source text extracted from routers/payment.py in a hand-built namespace, so the record_fallback/logger/sanitize calls added to the unresolvable-price branch raised NameError there. The test broke on the text of the function it copies, not on its behavior -- which is the argument for retiring source-parsing guards in favour of the catalog-wide check. * fix(web): make the MemoryCard timestamp assertion timezone-independent MemoryCard renders created_at through toLocaleDateString, which formats in the runner's local timezone. The fixture is UTC midnight, so the hardcoded 'Aug 1, 2026' label is 'Jul 31, 2026' on any runner behind UTC and the layout test failed for a reason unrelated to the layout it guards. Already broken on main; it blocks the pre-push web lane for every change touching web/app. Derive the expected label the same way the component does. * feat(firestore): register the hourly-usage plan-attribution query M1's get_usage_by_plan adds a year==/month== compound query on the per-user hourly_usage subcollection, which the coverage ratchet correctly flagged as a new unregistered serving shape. Register it as a query spec rather than baselining it -- baselining a brand-new shape is what the ratchet exists to prevent -- and regenerate firestore.indexes.json from the registry. * fix(plans): fail clearly on an unlimited basic transcription allowance pyright flagged two real errors in the new code. allocation_limit returns None for an unlimited allocation, so the module-level '_BASIC_TIER_SECONDS_DEFAULT // 60' would raise TypeError at import time if the catalog ever declared basic.transcription unlimited. Free is metered by design, so that is an authoring mistake; raise with a sentence that says so instead of crashing on an operator. Also drop the now-unused firestore import left behind in desktop_realtime.py by the cost-attribution work. * chore(api): regenerate the app-client OpenAPI contract cost_usd on RecordLlmUsageBucketRequest is now nullable without a 0.0 default, so an unreported cost stays unreported instead of being recorded as a measured zero. It is a request field, so existing senders are unaffected. No plan enum or plan-bearing response shape changed. * chore(api): regenerate TypeScript clients for the nullable cost_usd Single-line change in each generated client: cost_usd?: number becomes cost_usd?: number | null, matching the OpenAPI regeneration. * fix(plans): restore chat wording, and make the BYOK bypass tests real Three failures surfaced by a per-file isolated sweep of the backend suite. - Plan storefront copy regressed from '{N} chat questions per month' to '{N} questions per month' when the text moved into the catalog. That is user-visible product copy; a consolidation must not reword the product. Restored, with a note saying so. - test_stripe_webhook_none_guard asserted the literal source text 'except ValueError:', which the added telemetry turned into 'except ValueError as e:'. Third source-parsing test in this PR to break on wording rather than behavior; matched on the handler instead. - The BYOK transcription-bypass tests patched utils.byok.get_byok_key, but subscription.py binds that name at import, so the patch never applied and the bypass branch never executed. They passed at base by falling through to the plan-limits path and returning True for an unrelated reason -- the bypass they are named for had no coverage. Patch subscription's own binding and assert the subscription is never consulted, so the short-circuit is actually proven. * fix(plans): legacy zero overlays keep meaning unlimited Independently found by both review passes (codex sol P2, cursor grok P1), and the most consequential defect in this branch. Production sets BASIC_TIER_WORDS_TRANSCRIBED_LIMIT_PER_MONTH and BASIC_TIER_INSIGHTS_GAINED_LIMIT_PER_MONTH to literal '0' on the pre-catalog convention where 0 meant unlimited. Reading them as a finite zero would have given every Free user a zero words/insights allowance and advertised '0 words transcribed per month'. Retiring the sentinel is right; silently reinterpreting already-deployed configuration is not, and it contradicted this PR's own claim that production behavior is unchanged. Legacy overlay values are now read through _legacy_overlay_value, which maps a legacy 0 to unlimited. Applied to the minutes overlay too: charts set 300 so it was latent, but a deployed 0 there would have made has_transcription_credits return False for every Free user. Also: attribute the residual on MIXED usage documents. The first post-deploy write adds plan_usage to a document that already carries pre-deploy root counters; keying only on plan_usage's absence dropped that earlier usage from per-plan reporting entirely. And correct the design doc, which still described B1/B3 as open after the rulings landed. * refactor(plans): assign the Free transcription constants once, with clean types pyright rejected the branch-per-constant form (reportConstantRedefinition) and the string sentinel widened the overlay type to int | str. Return (present, value) from _legacy_overlay and compute both constants in one helper, so each is assigned exactly once and the unlimited case stays typed Optional[int]. * fix(plans): give the Free transcription default a narrowed int type pyright does not carry the module-level None check into the helper's body, so '_BASIC_TIER_SECONDS_DEFAULT // 60' still read as an Optional operand. Narrow once after the guard and annotate the constant as int. * refactor(plans): Stripe owns price amounts; the catalog owns price identity David's ruling, 2026-08-20, revising the original Q1 answer. The repository now stores no dollar amount at all. payment.py already calls stripe.Price.retrieve and renders unit_amount live, so the storefront has always shown Stripe's number; every in-repo dollar figure was display copy, a comment, or a test fixture that nothing compared against Stripe. Removing them dissolves the price-drift problem instead of guarding it -- with one copy there is nothing to drift, and changing a price touches no repository file. Deleted: the amount field on every catalog price, publication_state, the prepare/promote state machine (validate_stripe_publication, price_spec_digest, the --bindings/--stripe-snapshot flags) and its tests, and the publishable gate's 'price has not been imported' errors. Work items P1 and P2 are withdrawn. Kept: the append-only price-id -> plan ledger. Stripe cannot supply that mapping -- it does not know our plan enum -- and an unrecognised price id is exactly what dropped paying subscribers to free in the Apr 17-20 incident. In Git it gets code review, history, and a local lookup that survives a Stripe outage. Storing it in Stripe price metadata was considered and rejected: a typo would become a subscriber-affecting bug with no review and no audit trail. Verified: all ten production and dev price ids still resolve to the correct plan. * fix(desktop): let flow lint see the bridge extension files DesktopAutomationBridge was split into +Notifications and +ChatFirst extension files, but ACTION_SOURCE_RELATIVE_PATHS still listed only the base file. The lint therefore could not see actions those extensions register and reported notifications-settings.yaml as referencing two unknown bridge actions -- a valid flow failing against a stale file list. This was red on main, failing desktop-core-e2e-t0 for every PR touching desktop and blocking the pre-push gate. The contract file's own comment asks for exactly this list to stay complete so an added action cannot skip flow validation. desktop-flow-lint now reports OK: 72 flows, 162 registered actions. * fix(app): drop the now-unused subscription import in settings_drawer The analyzer ratchet allows zero unused_import and reported one. It is ours by reclassification: converting PlanType from an enum to a class changed what models/subscription.dart exposes, so settings_drawer's import went from unnecessary_import (baseline 11, now 10) to outright unused. Nothing in the file referenced a subscription symbol. Verified: analyzer ratchet passes, flutter test 1400 passed / 5 skipped. * test(desktop-chat): stop the BYOK exclusion test building a real Firestore client CI's hermetic network guard failed test_record_usage_skips_byok_requests with BlockedNetworkError against the GCP metadata server. The BYOK skip path passes firestore_client=get_customer_firestore_client(), which is evaluated before the stubbed recorder runs, so a real client was constructed and resolved credentials. It passed locally only because gcloud ADC credentials were present. Stubbing the factory in the test is the correct fix rather than dropping the argument: record_llm_cost_exclusion falls back to the default 'db' when given None, not to the customer client, so removing it would silently change which database exclusions are written to. Verified: 78 passed in test_desktop_chat.py. * fix(usage): stop double-counting attributed questions as unattributed Findings from a glm-5.3 review sweep, each verified against the code first. HIGH -- my own residual-attribution fix was wrong. It read the attributed total from plan_data['questions'], a field no writer writes: questions live at plan_usage.{plan}.{bucket}.quota_questions. The attributed sum was therefore always 0, the residual was the document's FULL root count, and every post-deploy document was counted twice -- once against its real plan and once against _unattributed. questions_by_plan summed to ~2x the truth and fed the per-plan report that MEASUREMENT_CONTRACTS['chat'] points at. Quota enforcement reads the root counters, so no entitlement impact. Now sums recursively the way _accumulate_plan_data traverses, and only creates an _unattributed row when the residual is actually positive. Two regression tests, both failing before. LOW -- the fallback telemetry I added used reason='unrecognized_price', which is not in ALLOWED_REASONS, so bucket_reason relabelled it 'other' and the reason dimension was lost. Now 'config_incomplete'. LOW -- lookup_key validation sat inside the currency-invalid branch, so it only ran when the currency was already wrong. It was publication-machinery schema with no consumer left; removed rather than repaired. Docs: the bridge covers only the Basic overlay family (the chat and Plus overlays are deliberately unbridged because nothing deploys them) -- the doc claimed all three and named a function that does not exist. Also corrected stale claims that survived the publication deletion: catalog-owned 'price amount in minor units', the deleted snapshot validator, --require-publishable reporting P1, and B1/B3/D1 still listed as open. Recorded an unverified dev-Architect ledger gap rather than appending IDs on the evidence of a test comment. | 10 天前 | |
fix(desktop): keep Interject PTT cards readable and barge-in on the live path (#12499) A mounted Interject card kept losing to listening island size after PTT-up, and hub_warm was committing omni while barge-in replacement was still connecting — so the later Gemini ready callback was stale, replay was discarded, and selected-voice fallback died on playback_drain. Notification chrome now wins collapsed size. hub_warm during recording replacement defers omni fallback; replacement-ready stays admissible and restores the manager-owned warm rescue. Fallback drain keeps the playing owner; native realtime remains fail-closed. Failure-Class: new Co-authored-by: Cursor <cursoragent@cursor.com> | 8 小时前 | |
chore(dev): add personal build config overlay for local dev builds (#11789) Introduces a .personal_configs/ convention at the repo root for contributors to store machine-local Firebase credentials and dev env config without committing them. Run app/setup-personal.sh after setup.sh to copy them into place. Split out of #7641 at maintainer request (community-build signing fix and this overlay are unrelated concerns and easier to review apart) — carries the same content as that PR's commits 1295dc33a2/b246990fa9, rebased onto current main. Failure-Class: none | 13 天前 | |
fix(release): qualification evidence CLI accepts the beta artifact names The workflow passes --asset Omi.Beta.zip/omi-beta.dmg but the CLI arg whitelist still allowed only the stable pair, exiting before build_evidence. CLI now accepts ARTIFACTS + BETA_ARTIFACTS; build/verify still require exact pairs. Regression test drives the real CLI subprocess with all four assets. Failure-Class: none Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> | 1 个月前 | |
feat(telemetry): close mobile lifecycle and device gaps (#11539) * feat(telemetry): standardize mobile app context * feat(telemetry): record mobile account creation * feat(telemetry): add mobile app sessions * feat(telemetry): normalize mobile search events * feat(telemetry): add mobile hardware family * feat(telemetry): distinguish hardware identity * feat(telemetry): instrument firmware updates * feat(telemetry): propagate recording firmware context * feat(telemetry): record subscription plan changes * feat(telemetry): add mobile recording lifecycle identity * feat(telemetry): instrument recording upload lifecycle * test(telemetry): align mobile context assertions * fix(app): bound analytics package metadata lookup Package metadata enrichment now shares the analytics initialization timeout so a missing or unresponsive platform plugin cannot block event delivery. Adds a regression test for the hanging method-channel path and initializes package metadata in the permissions analytics widget test.\n\nVerification:\n- flutter test test/unit/analytics_manager_package_info_timeout_test.dart test/widgets/permissions_interstitial_analytics_test.dart test/unit/analytics_manager_fail_open_test.dart --reporter expanded\n\nFailure-Class: none * fix(telemetry): close capture lifecycle gaps Focused Flutter tests pass for capture telemetry, device analytics, device families, and DAT DFU guards. Failure-Class: none * fix(capture): reject stale transcription socket results * fix(telemetry): classify upload HTTP failures * fix(telemetry): normalize unavailable firmware versions Failure-Class: none * docs(telemetry): keep event catalog off the public docs site Main removed docs/analytics/events.md from docs.omi.me. Preserve 11539's mobile telemetry dictionary in web/admin/docs/posthog-events.md, and update test overrides for main's geolocation and clientConversationId signatures. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: axAilotl <231548431+axAilotl@users.noreply.github.com> Co-authored-by: Max Carter 祁明思 <undivisible@users.noreply.github.com> Co-authored-by: David Zhang <david@scalingforever.com> Co-authored-by: Cursor <cursoragent@cursor.com> | 7 小时前 | |
SCA-393: add chat-quota reset-month to the admin usage CLI (#12500) * feat(backend): add chat-quota reset-month to the admin usage CLI Support often needs a current-month chat-quota reset, not listening minutes. Extend show to print both quotas and add reset-chat-month so operators can zero quota_questions without wiping telemetry or touching fair-use writes. Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: multica-agent <github@multica.ai> * feat(backend): make admin CLI skip unlimited listening resets show now prints listening throttled / chat included exhausted so operators do not goodwill-zero Operator minutes that never throttle. reset-month exits 2 on unlimited listening unless --force. --------- Co-authored-by: David Zhang <9387252+Git-on-my-level@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: multica-agent <github@multica.ai> | 7 小时前 | |
docs(backend): move calendar-capture rules to docs/agents/calendar-capture The Service Map bullet for the SCA-381 calendar-capture contract pushed backend/AGENTS.md past the agents-md-lean budget; keep the one-line contract there and move the full discard-override / auto-link gating / capture-gap rules to docs/agents/calendar-capture.md. | 23 小时前 | |
Add desktop backend parity contract tests | 2 个月前 | |
feat: add JIT knowledge ledger foundation and guarded adoption (#12084) * feat: add JIT knowledge ledger foundation * chore: refresh integration OpenAPI contract * fix: make trigger evaluation release-safe Failure-Class: none * fix: preserve lifecycle semantics in ledger apply Failure-Class: none * feat: adopt guarded JIT knowledge surfaces Route the agent preference writer through the intent-backed ledger, register a privacy-filtered entity timeline tool, render optional evidence on Windows, and add a base-ref-protected Gate F legacy-surface ratchet. Failure-Class: none * feat: add progressive JIT knowledge reads Register owner-scoped current-ledger search and explicit playbook hydration, with pre-limit semantic filtering and bounded outputs. Add a content-free planner/resume migration fixture without claiming canonical transaction completion.\n\nValidation: 141 focused backend tests passed; backend typecheck reported 0 errors; repository preflight passed 120 checks. * feat: render chat evidence on web Render bounded, fail-soft conversation evidence after authoritative answers in both web chat entry points. Unsupported, future, duplicate, and raw failure details remain inert.\n\nValidation: 337 web tests passed; web typecheck, oxlint, and Prettier passed; repository preflight passed 120 checks. * feat: require intent-backed ledger search results Apply the intent-backed requirement at the final merged canonical/history filter, with a passive historical-row regression case.\n\nValidation: 54 focused backend tests passed. * test: keep agent tool isolation stubs current * feat: gate JIT conversation retrieval * fix: make entity timeline scans deterministic Failure-Class: none * fix: honor rejected ledger projections Failure-Class: none * feat: render inert screen evidence on web * fix: reuse canonical review projection Failure-Class: none * fix(web): await recap context effect Failure-Class: none * test: amortize preference tool isolation load Failure-Class: none * feat(app): add knowledge ledger review surface Failure-Class: none * feat(macos): use canonical ledger prompt projection Failure-Class: none * test(memory): classify legacy surface inventory roles Failure-Class: none * fix(app): preserve ledger history completeness state Failure-Class: none * feat(macos): preserve canonical ledger mirror metadata Failure-Class: none * fix(app): match canonical ledger ordering Failure-Class: none * test(api): prove ledger client schema parity Failure-Class: none * feat(memory): expose bounded ledger history Failure-Class: none * chore(api): generate ledger history clients Failure-Class: none * feat(retrieval): add bounded card participants Failure-Class: none * feat(macos): project ledger trigger watchlist Failure-Class: none * fix(clients): fail closed on ledger authority Failure-Class: none * feat(macos): expose bounded trigger snapshot Failure-Class: none * fix(memory): keep closed history read only Failure-Class: none * feat(app): disclose partial ledger history Failure-Class: none * test(macos): cover ledger trigger bridge Failure-Class: none * fix(app): use neutral ledger accents Failure-Class: none * chore(api): declare ledger history route policy Failure-Class: none * test(macos): remove unsafe JSON fixture unwraps Failure-Class: none * fix(memory): satisfy typed history boundary Failure-Class: none * fix(macos): require prompt snapshot authority Failure-Class: none * test(memory): prove ledger migration on emulator Failure-Class: none * feat(retrieval): emit bounded screen evidence Failure-Class: none * test(memory): classify maintenance retirement readiness Failure-Class: none * feat(macos): adapt Rewind metadata for triggers Failure-Class: none * test(retrieval): align screen timestamp contract Failure-Class: none * feat(memory): correct ledger facts by amendment Failure-Class: none * test(memory): prove ledger correction on emulator Failure-Class: none * feat(macos): harden local trigger observations Failure-Class: none * feat(agent): search bounded historical facts Failure-Class: none * test(macos): cover trigger observation adapter * fix(memory): gate historical fact retrieval * feat(memory): add gated JIT retrieval strategy * test(memory): prove mixed-version JIT runtime parity * chore(memory): keep JIT gate exports type-safe * refactor(memory): isolate JIT prompt contract * fix(conversations): round-trip owner-scoped references Accept the conversation:<id> references emitted by JIT result cards while retaining strict UUID-only bare IDs and share links. Restrict machine IDs to a bounded safe alphabet so evidence suffixes and path-like values fail closed. Failure-Class: none * test(memory): join JIT citations to evidence envelope * fix(retrieval): enforce JIT conversation search budget Cap JIT summary searches per request and bound database hydration to the projection limit before reads. Preserve the legacy path when JIT is disabled. Failure-Class: FC-unbounded-user-collection-in-prompt * fix(memory): keep JIT retrieval request scoped * test(macos): prove future JIT evidence stays inert * fix(memory): keep JIT card citations request-global Failure-Class: new * fix(retrieval): separate JIT hydration from search Treat gated owner-scoped references as exact hydration without searching transcript text for the reference. Charge every JIT candidate search to the shared four-search request budget, including snippet-bearing requests, while keeping exact hydration free and preserving released JIT-off UUID/share-link behavior.\n\nVerified:\n- cd backend && ./.venv/bin/python -m pytest tests/unit/test_conversation_jit_processing.py tests/unit/test_conversation_exact_reference_search.py -q (58 passed)\n- cd backend && uvx --from pyright==1.1.403 pyright -p pyrightconfig.json --pythonpath .venv/bin/python (0 errors)\n- git diff --check\n\nFailure-Class: FC-unbounded-user-collection-in-prompt * fix(memory): keep repeated JIT cards index-safe * fix(retrieval): satisfy JIT card type contract * fix(retrieval): hydrate collected JIT cards * test(app): preserve answers during delayed evidence requests * test(app): exercise production evidence composition * feat(memories): restore superseded ledger facts * fix(memories): reconcile reverted ledger facts * feat(memories): append reverted ledger facts * feat(memories): synchronize revert client contract * fix(memory): name ledger revert identity * fix(memories): type and enlarge revert controls * fix(memories): fence revert retries and refreshes * fix(memories): fence ledger revert authority * test(memory): count ledger revert rate limit * feat: expose agent-controlled historical facts * feat: reopen standalone ledger facts * feat: add fail-closed JIT QA bundle routing * feat: add safe local JIT QA backend stack * fix: harden isolated JIT QA stack * feat: add explicit multi-source entity timeline * feat(backend): add JIT rollout authority * feat(backend): fence every proactive paid boundary * fix(backend): release proactive quota on cancellation Release the reserved proactive quota exactly once when cancellation interrupts paid-boundary refresh or a provider retry, then re-raise cancellation without emitting retry telemetry. Add deterministic regression coverage for both cancellation points. Failure-Class: FC-proactive-quota-cancellation | new * fix(backend): make proactive quota cancellation safe Detach in-flight Redis reservations on request cancellation and release only admitted slots once they settle. Move direct-provider fallback telemetry behind the fresh paid-boundary rollout check so late kill or unknown decisions cannot report false recovery.\n\nFailure-Class: FC-proactive-quota-cancellation | new * fix(backend): preserve quota compensation during shutdown Keep late Redis reservation compensators outside the ordinary cancellable background-task drain. Desktop and main application shutdown paths now wait for these critical compensators before cancelling ordinary work, with deterministic blocked-thread and lifecycle-order regressions.\n\nFailure-Class: FC-proactive-quota-cancellation | new * fix(backend): use expiring proactive quota leases * fix(backend): make quota finalization clock-safe * fix(backend): isolate jit rollout control plane * fix(backend): close jit control plane safely * fix(backend): emit retry recovery after quota commit * test(backend): keep rollout app contract fast * feat(jit): add guarded proactivity and first-open policies * chore(desktop): mark jit policy as internal * test(desktop): cover jit proactivity policy flow * feat(backend): wire durable JIT first-open processing * feat(desktop): fence JIT proactivity runtime admission * feat: activate authoritative JIT proactivity runtime * fix: harden JIT proactivity authority * fix: close proactive runtime authority gaps * fix(jit): make first-open effects resumable * fix(jit): fence outstanding first-open work * fix(jit): resume app usage receipts * fix(jit): make app usage retries no-op Failure-Class: none * fix(jit): allow completed usage after app deletion Failure-Class: none * fix(jit): register first-open folder query Failure-Class: none * Fix first-open import isolation * feat(memory): govern ledger slots and prompt winners * feat(macos): stage guarded ledger prompt adoption * feat(jit): adopt authoritative ledger prompts on macOS * fix(jit): close ledger adoption authority leaks * fix(jit): reauthorize every ledger migration write * fix(jit): fence ledger cutover publication * fix: keep ledger prompt rollback reversible * feat(jit): add guarded frame request retention contracts * fix(jit): close frame retention authority and evidence lifecycle * fix(jit): make frame retention retries and cleanup durable * fix(jit): make frame evidence recovery and retention complete * fix(jit): close frame retention recovery gaps * Harden temporary frame retention and deployment * fix: harden JIT frame retention and consumption * fix: close JIT frame lifecycle recovery gaps * fix: unify JIT frame authority and retention Failure-Class: FC-split-mutation-authority * docs: keep frame retention guidance lean * fix: retire duplicate frame flag bindings Failure-Class: FC-split-mutation-authority * fix: register frame keyframe queries Failure-Class: FC-split-mutation-authority * fix: serialize frame retention deploys Failure-Class: FC-split-mutation-authority * test: cover frame pixel deletion ordering * style: format cumulative Dart changes * fix(app): retain permanent conversation photo fetches * fix: bound frame vision retention and authority * fix: drain terminal frame request metadata * chore: record internal ledger adoption change * feat(memory): add dark daily sweep authority * feat(memory): harden daily sweep fences and runtime seam * feat(memory): reconcile existing standing triggers in sweep adapter * fix(memory): harden daily sweep recovery and source fences * fix(memory): close daily sweep source producers * fix(memory): close daily sweep review findings * Add dark daily memory sweep authority and recovery * fix(memory): harden daily sweep rejection repairs * test(listen): stub onboarding admission in bootstrap regression The daily sweep PR fences onboarding mode behind the server-owned backend admission (get_backend_onboarding_admission), so the bootstrap regression test now simulates an admitted session instead of failing closed on a real Firestore read. Verification: focused test passes in 1.64s (previously failed after a 4m27s Firestore timeout); full test_listen_runtime_regressions.py + test_onboarding_question_start.py: 26 passed; black --check clean. * fix(memory): close daily sweep rollout and retry cursors * fix(memory): isolate daily sweep lifecycle and retry fairness * Harden daily sweep admission and completed-day staging * fix daily memory sweep reliability boundaries * preserve daily sweep invocation tombstones * close daily sweep invocation lifecycle fences * fix: keep daily sweep lifecycle cleanup active * fix: acquire ledger snapshot client off event loop * fix(memory): preserve migration tier fence without legacy growth * test(memory): prove legacy adjudication race fences * fix(dev): allow bounded ADC readiness refresh * test: keep ledger prepush deterministic * test(memory): register prompt receipt control path * fix(memory): fence ledger writer transitions * feat(backend): preserve closed ledger history in export * feat(memory): define ledger query semantics * fix(backend): fence trigger snapshots on final authority * fix(backend): bypass stale coalesced JIT refreshes * feat(macos): mirror bounded memory evidence Decode generated v3 evidence into a domain mirror, persist canonical bounded JSON through the memory cache, and preserve it across compatibility sync and older-local conflicts. Invalid, future-shaped, oversized, and over-count payloads fail closed without hiding memory text or granting prompt authority. Tests: xcrun swift test --package-path Desktop --filter ServerMemoryV17DecodingTests Tests: xcrun swift test --package-path Desktop --filter MemoryLedgerMirrorTests Tests: python3 scripts/check_desktop_test_quality.py Failure-Class: none * fix(macos): fence and classify memory evidence Keep generated memory fields independent from malformed evidence, distinguish absent valid and invalid evidence states, preserve prior evidence on invalid payloads, and gate replacements on a monotonic server timestamp so stale active evidence cannot resurrect redacted rows. Cover populated-table migration upgrades. Tests: xcrun swift test --package-path Desktop --filter ServerMemoryV17DecodingTests Tests: xcrun swift test --package-path Desktop --filter MemoryLedgerMirrorTests Tests: python3 scripts/check_desktop_test_quality.py Failure-Class: none * fix(macos): preserve evidence fences and scrub redactions Advance evidence revisions for identical valid payloads, fence stale active responses after a local edit, and remove artifact/device pointers from redacted evidence before canonical persistence. Tests: xcrun swift test --package-path Desktop --filter ServerMemoryV17DecodingTests Tests: xcrun swift test --package-path Desktop --filter MemoryLedgerMirrorTests Tests: python3 scripts/check_desktop_test_quality.py Failure-Class: none * chore(macos): record ledger evidence mirror * feat(macos): deep-link local evidence cards to Rewind * fix(macos): fence Rewind frame evidence version * fix(macos): validate Rewind evidence card availability * fix(macos): bind task detail Rewind navigation to local leases * fix(macos): fence Rewind citation owner handoff * chore(macos): register Rewind evidence deep links * test(macos): cover Rewind evidence navigation * feat(desktop): evaluate JIT trigger watchlists locally * feat(desktop): wire authoritative JIT trigger runtime * feat(desktop): bind JIT claims to snapshot authority * fix(desktop): revalidate trigger authority at execution * fix(desktop): keep JIT execution leases live * test(memory): bind standalone reopen to direct-user writer * fix: make JIT QA sign-in self-contained Failure-Class: new Verification: bash desktop/macos/tests/test-jit-qa-target.sh; bash desktop/macos/tests/test-yolo-dev-backend.sh; repaired named-bundle Google sign-in reached authenticated onboarding. * feat(memory): complete JIT policy and native Windows parity * docs(backend): keep service map within context budget * test(macos): cover JIT client and staging flows * chore(backend): declare JIT mirror route policy * fix(backend): use strict Firestore boundary for JIT admission Failure-Class: FC-malformed-doc-read * chore(quality): register malformed-document guard surface * fix(backend): fail closed on malformed JIT authority Failure-Class: FC-malformed-doc-read * refactor(backend): name JIT workflow boundary results * test: repair JIT CI contracts * fix(backend): preserve ledger query exports Retain the explicit same-name re-exports consumed by tests and downstream callers while satisfying the enforced Pyright unused-import boundary after the main rebase. Failure-Class: none * test(backend): isolate gateway setup timing Failure-Class: none * style(memory): format direct-user evidence path Failure-Class: none * test(agent): isolate ACP process-group fallback Failure-Class: none * fix(dev-harness): preserve ownership markers in narrow CI * test(jit): refresh emulator fixtures for current contracts * test(jit): orchestrate local rollout dogfood * test(jit): harden local dogfood authority * fix(dev-harness): install PostHog for CI tests * fix(chat): project server JIT rollout into retrieval Resolve the backend-owned PostHog decision inside the bounded agent setup path and pass only its boolean result to prompt/tool configuration. Unknown or failed authority remains on the released legacy path, while callers cannot self-enroll through configurable input.\n\nVerification: backend/.venv/bin/python -m pytest -q backend/tests/unit/test_chat_async_offload.py backend/tests/unit/test_atomicity_lifecycle_regressions.py (41 passed)\n\nFailure-Class: new * fix(memory): preserve preference writer compatibility Select the agent preference write path from the canonical per-user writer control. Default compatibility mode retains the released MemoryService payload and receipt behavior; ledger mode keeps the retry-stable ledger write, and transition states fail closed.\n\nVerification: backend/.venv/bin/python -m pytest -q backend/tests/unit/test_chat_async_offload.py backend/tests/unit/test_atomicity_lifecycle_regressions.py (41 passed)\n\nFailure-Class: FC-split-mutation-authority * fix(jit): separate migration rollout authority Keep staged JIT chat and proactive exposure independent from legacy-row migration and writer cutover. Migration now requires its own default-off PostHog flag and still rechecks the shared kill switch at every mutation and publication boundary. Repair the isolated conversation-JIT fixture for main's chat-scope import. Verification: 217 focused JIT, chat-scope, migration, and lifecycle tests passed; 28 conversation-JIT fixture tests passed; independent Sol review accepted the split for QA-only dev rollout. Failure-Class: FC-split-mutation-authority * fix(photos): preserve retained image retrieval Treat an empty legacy inline marker as absent when permanent storage is authoritative, while malformed non-empty inline payloads still fail closed. Route live and retained thumbnails through the storage-aware image loader and preserve the conversation identity through the full-screen viewer.\n\nVerification: backend data-export tests 32 passed; Flutter photo-viewer tests 5 passed; focused Dart analysis clean; independent Sol review found and verified the viewer identity repair.\n\nFailure-Class: none * fix(memory): keep disabled daily sweep dark Resolve the backend-owned authority before inventory and require its literal true decision before any UID discovery, registry, cleanup, scheduler, model, or commit work. Missing, malformed, throwing, disabled, and kill-switched authority now exits without touching user data; enabled behavior is preserved.\n\nVerification: 60 focused daily-sweep job, scheduler, and inventory tests passed; independent Sol review accepted the fail-closed gate.\n\nFailure-Class: FC-split-mutation-authority * fix(jit): satisfy fail-closed type contracts * test(backend): admit full runtime contract checks * style(backend): format conversation bound test * test(backend): keep conversation router isolation current * test(backend): admit export boundary duration * fix(macos): persist failed chat turn notice Failure-Class: none * fix(macos): repair JIT rollout admission contracts Failure-Class: none * fix(windows): treat JIT screen evidence as untrusted Failure-Class: none * fix(backend): preserve explicit app failure contract Failure-Class: none * fix(app): finish photo viewer consolidation * fix(backend): make provider writes lock-free against the deletion gate The account-wide legal-hold deletion gate wrapped every GCS upload and Pinecone/Typesense upsert in an exclusive per-uid Firestore mutex with no lease: concurrent same-account writes hard-failed (dropped audio, lost vectors) and a crash between acquire and finish blocked the account's gated operations forever, with no janitor. Provider writes now use a lock-free fence that refuses only during account deletion or a live destructive operation; destructive kinds keep exclusive ownership, an abandoned gate self-expires after six hours, and releasing a gate on the failure path can no longer mask the original error. Failure-Class: none Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(backend): issue onboarding admission at socket connect The completed-onboarding early exit returned False from an Optional[str] function; the listen runtime derives admission via 'is not None', so users who had already completed onboarding were admitted with a fabricated session id — the exact provenance forgery the admission exists to prevent. Separately, the 20-minute admission TTL was anchored to the app-launch state read, so a user reaching the speech-profile step late (or any client that never calls the state endpoint) silently lost onboarding questions and is_user tagging. The bootstrap now issues or refreshes the admission from the durable account state at connect time; completed accounts still can never re-enter, and issuing stays best-effort with the read failing closed. Failure-Class: none Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(backend): keep the released proactivity lane open for legacy clients Gating /v1/desktop/proactivity/completions on the JIT cohort returned 403 to every non-admitted user — which is the entire deployed desktop fleet on deploy day, since shipped clients poll this route continuously and treat 403 as a plain error. Context-bucket extraction and the director would have died fleet-wide, dark cohort or not, and any environment without a PostHog key (local, self-host) would have lost the lane entirely. The route returns to merge-base admission semantics (tier quotas only); JIT admission remains enforced on the JIT reservation routes, and retiring this lane stays a later explicit operation after clients migrate. Failure-Class: none Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(backend): withhold JIT tools and history reads outside the rollout Five new tools (search_knowledge, search_historical_facts, read_playbook, get_entity_timeline, look_at_frame) sat unconditionally in CORE_TOOLS, so every legacy chat request carried their schemas and the model burned tool budget on 'no entries found' answers. They are now filtered per request off the same resolved rollout boolean that gates the JIT prompt appendix. The memories-tab ledger-history endpoint likewise answered every user with a bounded 501-row provider scan that can only ever be empty outside the rollout; it now returns empty without the scan for non-admitted (and unknown/error) states. Failure-Class: none Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(backend): bound rollout control-plane cost and confine sync resolution Synchronous callers resolved rollout flags via per-call asyncio.run against the shared provider singleton, crossing event loops: awaiting a Task attached to another loop raises, a timed-out asyncio.run strands a coalescer entry that then serves stale UNKNOWN forever, and the LRU cache was mutated from multiple threads. Sync resolution now runs on one long-lived control-loop thread with its own authority instance. Unknown snapshots gain a 5-second negative cache — UNKNOWN can never authorize work, and without it a fleet whose flags are simply absent pays one uncached PostHog call per conversation finalization. The screen-sync loop drops its force_refresh (one uncached decide per device per minute fleet-wide) and moves to its own rate bucket so two Macs' background sync can no longer starve conversation photo reads out of the shared 120/hour frame-requests bucket. The first-open policy's kill-switch telemetry label also reported str(Enum) instead of the value and could never match. Failure-Class: none Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(backend): skip eager extraction under a non-compatibility writer mode A ledger-cutover user still ran the full L1 extraction model call at finalization, after which writer admission refused the compatibility write — the conflict retried, exhausted, and failed the entire finalization for every conversation, with the model spend already paid. Extraction now checks the canonical writer mode first and skips when the daily sweep owns memory formation; only a positively-read non-compatibility mode skips, so any control-state read failure preserves the legacy eager path. Failure-Class: none Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(backend): export tolerates byte-less legacy photo rows A conversation photo row carrying the legacy empty inline marker and no storage reference failed the whole portability export forever, though it holds no durable image anywhere — there is nothing to omit. Such rows now export as metadata with a content-free gap reason. Frame requests in a retained state keep the fail-closed contract via an explicit require_bytes parameter. Failure-Class: none Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(windows): harden JIT delivery, admission, and bootstrap boundaries Five verified defects: (1) the exclusive notification delivery slot leaked on any throw between reservation and commit — one SQLite hiccup during a JIT turn permanently silenced every proactive lane; the span is now try/finally-guarded and stale slots expire after ten minutes. (2) The ambient lane interpolated the raw window title into a tool-capable agent prompt; the turn now carries only the opaque context handle plus a sanitized executable name, framed as untrusted data like the nano-triage lane. (3) Google Calendar was fetched every ~60s before admission, so non-cohort users with Google connected paid ~1,440 reads a day for a refused feature; observation now gates calendar evidence on the cached authority. (4) Rollout-authority errors reset the cache and retried every frame (~1 req/s offline, forever); failures now back off from 30s to 10 minutes. (5) An unguarded JIT schema exec inside the shared database open could abort local storage for all features; the mirror bootstrap is now isolated, keeps the host-facing tables alive, and JIT stays inert when unavailable. Also re-checks the control-plane owner before committing the toast so an account switch mid-turn cannot show the previous owner's advice. Failure-Class: none Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(macos): restore screen provenance, guard migrations, fence chat turns Four verified defects: (1) every pre-existing screen-derived task lost its 'Screen context / Open Rewind' source row because the new evidence policy dropped any provenance that is not rewind_frame.v1; the merge-base fallback row is restored for capture.v2/legacy refs (a test flipped to match the regression is restored to its merge-base assertions). (2) RewindDatabase published its pool before migrating, latching a failed migration into a permanent false-initialized state, and three unguarded ALTER TABLE memories migrations died with duplicate-column on machines that ran earlier builds of this branch; migration now precedes publication and the ALTERs/CREATEs are existence-guarded. (3) EventKit was queried on every context visit before the flags check; non-admitted owners now build no observation inputs. (4) A failed chat turn's reconstructed notice could be appended into a different conversation's transcript when the user switched sessions or cleared chat mid-flight; both transcript resets now revoke the active turn like selectApp already did. The pre-terminalized discard class (user Stop/watchdog) still drops the durable notice on relaunch — pinned by a characterization test in agent/tests/conversation-journal.test.ts with the least-invasive fix described there. Failure-Class: none Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(testing): resolve firebase-tools from the checked-in dependency npx --prefix resolves the package bin against the current directory on some npm versions, and the admission runner deliberately launches from an isolated temp dir (firebase writes debug logs to cwd) — surfacing as 'sh: firebase: command not found' on hosts without brew node@22. Prefer the vendored node_modules binary when it matches the pin; npx remains the fallback. Failure-Class: none Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor(backend): keep one eager-extraction call site for the surface ratchet Failure-Class: none Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor(backend): gate eager extraction at the public boundary The writer-mode skip moves from _extract_memories_inner to extract_memories: the replace-policy contract test pins the inner helper to exactly the canonical replacement path, and the public boundary is the better seam anyway — a sweep-owned user now skips parity capture and usage tracking along with the model call. Failure-Class: none Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test(listen): stub onboarding admission issuance in bootstrap regression The connect-time ensure call landed in a harness that only stubbed the read, so the bootstrap test paid an extra real-module exception path and grazed the 0.30s fast-unit CPU budget under fanout load. Stub the issuance like the read. Failure-Class: none Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test(listen): allowlist the bootstrap regression's CPU budget The full listen-runtime bootstrap test measures exactly at the 0.30s fast-unit CPU budget under a saturated pre-push fanout (CPU inflates ~2x there per the guard's own notes) while passing comfortably alone. It exercises deliberately heavyweight machinery; record it as an intentional exception rather than trimming the coverage. Failure-Class: none Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(backend): keep list(CORE_TOOLS) literal through JIT tool gating The JIT-only tool filter replaced the list(CORE_TOOLS) assignment with an inline comprehension, which broke the prompt-cache structural invariant (test_prompt_cache_optimization.py::test_core_tools_used_in_both_functions). Restore the list(CORE_TOOLS) copy and apply the JIT-only filter as a conditional pass, preserving rollout semantics and tool order. * feat(jit): drop automatic goal updates from the JIT featureset Product decision (David, 2026-08-26): goals change only through explicit user action for JIT-admitted conversations. Goal progress is no longer a first-open obligation — the effect is removed from FIRST_OPEN_EFFECTS and the worker, and the policy plan can no longer express deferring it. Legacy obligations carrying a pending goal_progress row are normalized away and complete on the remaining two effects. Non-JIT (legacy eager) conversations keep today's automatic goal updates unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(sweep): one summary-spine agent pass per day, with folder backstop Replaces the per-conversation transcript extractor in the completed-day producer with a single two-phase agent run: the whole day's conversation summaries go in as one bounded spine (200 conversations / 120k chars — effectively unreachable, so heavy days no longer stall the cursor), and the agent may request up to 8 raw transcript excerpts (8k chars each) to verify specifics before finalizing. At most two provider calls per user per day, both inside the existing at-most-once invocation fence; the staged page carries the memory candidates AND folder assignments for the day's unopened, unfiled conversations, applied idempotently (first-open or user assignment always wins). Memories must cite their source conversations; uncited output is dropped. The cost gate becomes a worst-case ceiling checked before any call. The onboarding cold-start channel keeps per-conversation transcript extraction unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(sweep): harden the daily agent prompts from a real-data lab pass Iterated on one real heavy day (26 conversations) with strong- and weak-model stand-ins, an adversarial judge, and hand-verified transcript ground truths. Rules added, each pinned to an observed failure: actor binding in active voice with a personal-attribute gate (a discussed or recommended topic is never someone's attribute; judgments about named people are stored as assessments); decision-state basis labels binding the verb (decided/proposed/observed, discussed-no-outcome dropped); salience ordering (money, metrics, named-party intent, identity, and durable decisions before any operational fact; one fact per memory); never guessing the direction of an invitation/offer/commitment (verify or drop); and no deferring the whole answer to verification. The agent output schema gains a 'basis' field. The memories QoS call-site inventories now count the daily-sweep agent's call site (3 -> 4). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(sweep): tune the daily agent prompts against the real memories model Ran the assembled prompts against gpt-5.6-luna (the real 'memories' route model) on the same real day. Three refinements from observed behavior: the basis label no longer leaks into memory text (metrics read as metrics, not 'David observed that…'); the never-guess-direction trigger is mechanical (passive/verbless summary phrasing or 'Speaker' as the actor forces a transcript_request — luna confidently inverted 'Tim: Invited to New York' until this; with it, phase B verifies and corrects to the true direction), hedging is itself a request signal, and nothing high-salience may be silently dropped; and a rich-day yield anchor (8-16 memories for 15+ conversations) counters the model's over-pruning without inviting padding. Final real-model run: 11 true memories + 2 legitimate verification requests, zero fabrications, ~22k tokens (~2 calls) for a 26-conversation day. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(sweep): profile-maintaining slots, ledger lookups, cache-ready prompts The daily agent now sees the user's current profile (the same get_prompt_memories seam chat uses — the ledger render for migrated users), may run up to 4 owner-scoped prior-memory keyword lookups (provider fail-soft; hits re-read through the canonical store before disclosure) to dedup and supersede, and may name a slot for standing attributes — an occupied slot becomes an amend through the existing canonical occupancy check, so the daily run maintains the rendered profile with no second write path. Both phase prompts share a byte-identical prefix (pinned by a test) and pass a per-user prompt_cache_key through get_llm; measured against gpt-5.6-luna the provider cache is exact-match rather than prefix-based today, so this is future-proofing rather than present savings. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(sweep): type the memory-searcher seam for the pyright contract CI's authoritative typecheck rejected the untyped lookup seam (memories.py: list(Any or [])). The searcher is now Optional[Callable[[str], Sequence[str]]] and results are built through a typed comprehension; behavior unchanged (absent or failing searcher still degrades to an empty result block). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix: repair four main-inherited CI breakages after sync origin/main is currently red on its own tip; syncing it into this PR inherits the breakage, so the fixes ride here: - subscription.py: drop the unused get_byok_keys import (pyright reportUnusedImport fails the Backend unit suite). - AppState+Transcription.swift: explicit self for alertPresenter inside the escaping showAlert completion (strict-concurrency compile error in all three Desktop Swift lanes, shipped red on main by d49f978512). - AppState+Permissions.swift: pinned swift-format drift from the same main commit (desktop-swift-format-lint). - web/app/bun.lock: add the prettier + prettier-plugin-tailwindcss entries 64db30c791 pinned in package.json without updating the lockfile (frozen install fails web-app-checks). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(sweep): close the second review round's findings Three parallel adversarial reviews over the post-takeover additions: - Clamp every model-controlled phase-B input (draft memories, request reasons, lookup queries/results) and add the clamped worst case to the pre-call cost ceiling, which previously under-estimated phase B. - Attest an empty consumed day when the staged page carries an older stage schema version instead of stalling the cursor forever on every deploy-boundary schema bump. - Make the folder backstop's unfiled check and write share one transaction so a concurrent first-open/user assignment always wins. - Let equal-rank sweep candidates amend sweep-authored slot occupants: the profile-maintenance path froze after a slot's first write. User statements still always win; slotless subject matches still dedup. - Neutralize ``` fences in summaries/excerpts/lookup results, and mark raw-transcript fallback rows '(unstructured transcript excerpt)' with a prompt rule refusing slots/personal attributes from them without transcript verification (test pins the marker to the rule). - Remove the dead first-open goal-authority threading left by the goals removal, and update the stale jit-first-open-runtime doc. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix: repair three more main-inherited breakages All shipped red on main and only surfaced once earlier failures were cleared: - AppState.swift: move the alertPresenter default out of the stored property initializer — Xcode 16.4's SILGen segfaults (signal 11) emitting it, which failed all three Desktop Swift lanes even after the explicit-self fix. - test_byok_security.py: main's BYOK rewrite (d0e3a4eb3a, 1da8880175) changed request_has_llm_byok_key to per-provider enrollment checks and made partial headers fail closed, but left the tests targeting the old get_byok_keys()-based lenient contract (masked on main because pyright failed before pytest ran). The tests now assert the shipped strict contract their own docstrings already describe. - subscription.py: pinned-black formatting for the BYOK fallback expression (the Formatting lane rejects the file as main wrote it). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(tests): stub the chat-agent gateway route pin in the chat router harness Main's a6988be309 made routers.chat import CHAT_AGENT_ROUTE_DIRECT / get_chat_agent_route from utils.llm.gateway_client, but the chat-router test harness (and test_chat_file_upload_unsupported's local override) stub utils.llm.gateway_client without those symbols, so every suite that loads the real router failed at import — masked on main because pyright fails its Backend unit suite before pytest runs. Ninth main-inherited repair in this sync. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(tests): teach test_chat_quota's utils.byok stub the rewritten import surface utils/subscription.py now imports get_byok_uid and get_cached_byok_state (main's BYOK rewrite); the module-scoped utils.byok fake predates them, so reloading subscription under the fake raised ImportError at setup — and the polluted process took test_chat_openapi_operation_ids and test_desktop_screen_crisp down with it in CI's batched run (all three pass standalone). Tenth main-inherited repair, same pyright-masked pattern. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(tests): update three more suites for main's BYOK/gateway import surface Same pyright-masked pattern as the harness and test_chat_quota repairs: - test_desktop_transcribe stubbed utils.llm as a non-package, so routers.chat's new utils.llm.gateway_client import could not resolve (50 failures); the submodule is now in its stub list. - test_paywall_reconnect_gate's BYOK escape-hatch tests never set the request uid context that the enrollment-verifying rewrite requires (middleware sets it in production); they now do, and teardown clears it. - test_chat_session_app_identity's enforce_chat_quota stub rejected the new required_llm_provider keyword. All three suites pass locally (69 + 35 + 6). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(tests): enroll fingerprints in the desktop BYOK tests PR #11454 moved macOS BYOK activation to enrollment-verified fingerprints (isByokActive and usableBYOKEnvironment gate on persistEnrolledFingerprints), and its own test lanes shipped red: the tests store raw keys but never enroll them, so every key reads as inactive. Their teardowns already clear enrollment — the setups now enroll what they store, matching the production activation path. All 8 previously-failing cases (BYOKPaywallTests + the two AgentRuntimeProcessTests BYOK-environment cases) pass locally. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(deploy): enable the daily memory sweep on development The sweep's five deployment inputs were pinned off in every environment, so cohort enrolment alone could never start it -- turning it on for a dogfood account required a second PR. Development now carries the live values: - ENABLED/MODEL_ENABLED on, so the job stops exiting at its first authority gate and the model authority can budget a route. - MODEL_NAME pinned to gpt-5.6-luna, which is the declaration interlock the runner checks against get_model('memories') before any provider call. - MAX_MODEL_COST_USD 0.80, the worst-case pre-call ceiling for a maximal day including phase B's clamped draft/reason/lookup overhead. - COHORT_ENABLED on with COHORT_FLAG daily-memory-sweep-v1, so enrolment is a per-uid PostHog boolean and an unnamed cohort stays a closed rollout. Production is deliberately untouched and stays fully pinned off. The job still cannot form a memory for anyone until that flag exists and resolves true for a uid, which remains a control-plane action rather than a deployment one. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(firestore): terminate the daily-sweep occupant indexes with __name__ The six daily-sweep occupant lookups were the only declarations in the manifest without a trailing __name__ field -- 63 of 69 entries carry one, and main had none missing it. Firestore appends the terminator itself and reports the index back that way, so these six could never match the live inventory. The failure mode is not a missing index; the indexes build fine. It is that reconciliation never converges: every run reports the same six as missing, tries to create them, and fails on ALREADY_EXISTS. That takes down the Firestore schema workflow on both environments permanently, and with it the development backend deploy's readiness gate -- the same class of outage the workflow's own header records from the hourly_usage index in PR #11979. The derived specs previously appended their extra predicates to the base spec's index_fields, which would have placed them after the terminator, so the shared prefixes are now named explicitly and each spec ends with __name__. Verified against real Firestore: reconciliation reports zero missing indexes in both based-hardware and based-hardware-dev. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix: close final JIT rollout and CI gaps Fence direct JIT tools and frame pixels, keep Windows account wipes safe after optional schema failures, and repair inherited CI regressions. Failure-Class: none --------- Co-authored-by: David Zhang <9387252+Git-on-my-level@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> | 4 天前 | |
chore: consolidate changelog for v0.12.252 | 8 小时前 | |
chore(backend): export app-client OpenAPI for /v1/calendar/capture-gaps Regenerated with backend/scripts/export_openapi.py --surface app-client --write; adds the CalendarCaptureGap schema and the capture-gaps path. Dart wire models unchanged (generate_dart_models.py --all --check passes; the app uses a hand-written CalendarCaptureGap adapter like CalendarEventLink). | 23 小时前 | |
fix(devops): guard WIF pilot partial recovery The development bootstrap stopped after two desired resources because the WIF display names exceeded the IAM API limit. Bound both labels and accept only the recorded two-resource state plus the remaining three creates during recovery. | 1 个月前 | |
docs: update MCP setup for OAuth and manual clients (#11298) * docs: update MCP setup for OAuth and manual clients * docs: make MCP Python example runnable | 22 天前 | |
chore(firmware): remove dead software-VAD Kconfig; scope silence tuning under T5838 AAD (#12101) Implemented-By: codex gpt-5.6-sol Co-authored-by: Claude Fable 5 <noreply@anthropic.com> | 4 天前 | |
fix(security): resolve Dependabot security vulnerabilities across workspace (#10875) * fix(backend): update vulnerable python dependencies to patch ranges (~=) * fix(desktop): update vulnerable dependencies in desktop apps to patch ranges (~) * fix(web): update vulnerable dependencies in web applications to patch ranges (~) * fix(sdks): update vulnerable dependencies in react-native sdk and example to patch ranges (~) * fix(mcp): update vulnerable python dependencies in mcp server to patch ranges (~=) * fix(plugins): update vulnerable python dependencies in plugins to patch ranges (~=) * fix(docs): update vulnerable dependencies in docs to patch ranges (~) * fix(omiGlass): update vulnerable dependencies in omiGlass to patch ranges (~) * fix(root): update vulnerable dependencies in root package to patch ranges (~) * fix(windows): apply pnpm security overrides * fix(windows): align electron-builder package family Failure-Class: none Verification: pnpm install --frozen-lockfile; pnpm exec electron-builder install-app-deps; pnpm run typecheck; pnpm run lint; git diff --check. * fix(deps): pin runtime requirements to locked versions Make PR-updated Python runtime requirements exact pins matching their committed backend locks; make MCP's lock-backed constraint explicit and remove its unresolved constraint. Validation: backend/scripts/sync-python-deps.sh; backend/test.sh; mcp uv lock --locked; mcp pytest; locked npm/pnpm resolutions; make preflight. Failure-Class: none | 1 个月前 | |
feat(conversations): add coherent cached notes pipeline Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> | 13 天前 | |
docs: take operator pages off docs.omi.me Unlisted Mintlify MDX is still a public URL. Move runbooks, flags, invariants, and agent rules next to owning code, add docs/AGENTS.md as the site allow-list, and correct the live kill-switch contract after the JIT authority page leaves the site. Co-authored-by: Cursor <cursoragent@cursor.com> | 1 天前 | |
fix: make Pusher finalization releases fail closed Failure-Class: FC-rollout-flag-absent-from-a-cohost-of-its-code-path | 1 天前 | |
feat(dev-api): add /v1/dev/user/ask and omi ask CLI (#11452) * feat(dev-api): add omi ask on current main * fix(dev-api): harden ask retrieval and request validation * chore: retrigger Repo Checks after Line-Count-Exception base bump PR body now declares backend/routers/developer.py | 2111 -> 2225 to match current main. * test(cli): cover the --timezone option boundary on omi ask Reviewer note on #11452 asked for an option-boundary test once backend timezone validation was defined. It now is (DeveloperAskRequest rejects non-IANA values), so this pins the CLI half of the contract: the default is UTC and an explicit --timezone is forwarded verbatim rather than pre-screened client-side, where a second IANA list would drift from the server's ZoneInfo database. Verified the test guards rather than decorates: hardcoding "UTC" in main.py's request body fails it (assert 'UTC' == 'Asia/Kolkata'); restored and the file's 3 tests pass. * chore(api): regenerate app-client TypeScript clients after the main merge * chore(api): regenerate the Swift app-client after the main merge * chore(ci): retrigger desktop Swift CI after an unrelated flake Desktop Swift Static & Test Contracts failed on SuggestedTasksStoreTests.testNotMineAndAlreadyHandledPersistReasonAndResolveCandidate, a task-intelligence test in a subsystem this PR does not touch. The same CI window produced two other unrelated Swift test failures on other PRs, each a different test. No code change. | 6 天前 | |
feat(telemetry): close mobile lifecycle and device gaps (#11539) * feat(telemetry): standardize mobile app context * feat(telemetry): record mobile account creation * feat(telemetry): add mobile app sessions * feat(telemetry): normalize mobile search events * feat(telemetry): add mobile hardware family * feat(telemetry): distinguish hardware identity * feat(telemetry): instrument firmware updates * feat(telemetry): propagate recording firmware context * feat(telemetry): record subscription plan changes * feat(telemetry): add mobile recording lifecycle identity * feat(telemetry): instrument recording upload lifecycle * test(telemetry): align mobile context assertions * fix(app): bound analytics package metadata lookup Package metadata enrichment now shares the analytics initialization timeout so a missing or unresponsive platform plugin cannot block event delivery. Adds a regression test for the hanging method-channel path and initializes package metadata in the permissions analytics widget test.\n\nVerification:\n- flutter test test/unit/analytics_manager_package_info_timeout_test.dart test/widgets/permissions_interstitial_analytics_test.dart test/unit/analytics_manager_fail_open_test.dart --reporter expanded\n\nFailure-Class: none * fix(telemetry): close capture lifecycle gaps Focused Flutter tests pass for capture telemetry, device analytics, device families, and DAT DFU guards. Failure-Class: none * fix(capture): reject stale transcription socket results * fix(telemetry): classify upload HTTP failures * fix(telemetry): normalize unavailable firmware versions Failure-Class: none * docs(telemetry): keep event catalog off the public docs site Main removed docs/analytics/events.md from docs.omi.me. Preserve 11539's mobile telemetry dictionary in web/admin/docs/posthog-events.md, and update test overrides for main's geolocation and clientConversationId signatures. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: axAilotl <231548431+axAilotl@users.noreply.github.com> Co-authored-by: Max Carter 祁明思 <undivisible@users.noreply.github.com> Co-authored-by: David Zhang <david@scalingforever.com> Co-authored-by: Cursor <cursoragent@cursor.com> | 7 小时前 | |
fix(release): admit the sanctioned Omi Beta assets in qualified-beta promotion The single-artifact hardening added a retired-identity guard that rejects Omi.Beta.zip/omi-beta.dmg — so promote-qualified failed every INV-BETA-1 candidate at the final admission step. The sanctioned pair is now allowed (any other 'omi beta' name stays retired), downloaded, digest-checked, and verified against the qualification evidence's four-artifact set. Older single-identity releases are unchanged. Regression: build_qualified_beta_manifest admits a beta candidate and still rejects a non-sanctioned 'Omi Beta.zip' identity. Failure-Class: none Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> | 1 个月前 | |
Add Cursor compatibility: rules, commands, skills, subagents, and documentation - Add comprehensive Cursor rules for backend, Flutter, firmware, web, and plugins - Add Cursor commands for setup, testing, deployment, and development workflows - Add specialized skills for Omi patterns (backend, Flutter, firmware, API, plugins) - Add subagents for specialized development roles - Add architecture and component documentation in .cursor/ - Add index files for docs, backend, and app directories - Add .cursorignore for proper file exclusion - Apply cursor-best-practices: keyword-rich descriptions, proper frontmatter, clear purposes | 7 个月前 | |
fix backend runtime config validation | 2 个月前 | |
docs: add direnv example for optional local env loading Co-authored-by: Cursor <cursoragent@cursor.com> | 2 个月前 | |
fix(macos): match realtime voice and preserve long playback Co-authored-by: multica-agent <github@multica.ai> | 3 天前 | |
docs: add design-context brief (.impeccable.md) for UI agents | 1 个月前 | |
point hook docs at make setup | 2 个月前 | |
Keep generated TS contracts deterministic | 1 个月前 | |
fix: address cubic bot review — 7 issues across 4 files run-pre-push.sh: - P1: Fix command execution bug — use `git rev-parse` instead of bare ref (was trying to execute remote ref as shell command) - P2: Use detected base branch instead of hardcoding origin/main run-lint.sh: - P1: Fix reversed black logic — --check mode now correctly passes --check to black, fix mode omits it - P2: Remove unsupported --fix flag from pre-commit run (pre-commit auto-fixes via individual hooks, not a global flag) - P2: Same --fix removal in all-files mode .secrets.baseline: - P1: Tighten exclude regex patterns with proper anchors (^|/) and (/|$) to prevent overly broad matching (e.g., 'build' no longer matches filenames containing that substring) .pre-commit-config.yaml: - P2: Remove ruff-format hook (conflicts with black — ruff docs state they are not intended to be used interchangeably due to known output deviations; keep black as sole formatter) | 2 个月前 | |
docs: take operator pages off docs.omi.me Unlisted Mintlify MDX is still a public URL. Move runbooks, flags, invariants, and agent rules next to owning code, add docs/AGENTS.md as the site allow-list, and correct the live kill-switch contract after the JIT authority page leaves the site. Co-authored-by: Cursor <cursoragent@cursor.com> | 1 天前 | |
docs(agents): collapse five CLAUDE.md pointers into one Each component carried a CLAUDE.md whose only content was 'read AGENTS.md', so every rename had to be mirrored in two files and the root pointer had already drifted -- it advertised desktop/CLAUDE.md and desktop/e2e/SKILL.md, neither of which exists. Keep exactly one CLAUDE.md at the repo root, and have it tell agents to treat AGENTS.md as the instruction file and read the nearest one above their work. That removes the dual-state maintenance and also reaches .github/AGENTS.md, which had no CLAUDE.md sibling and so was never auto-loaded at all. | 1 个月前 | |
docs: take operator pages off docs.omi.me Unlisted Mintlify MDX is still a public URL. Move runbooks, flags, invariants, and agent rules next to owning code, add docs/AGENTS.md as the site allow-list, and correct the live kill-switch contract after the JIT authority page leaves the site. Co-authored-by: Cursor <cursoragent@cursor.com> | 1 天前 | |
chore: update triage guide with new label system - Add GitHub Labels section with exact label names and colors - Layers: capture, understand, memory, intelligence, retrieval-action, ux-polish, docs-tooling - Priorities: p0, p1, p2, p3 - Lanes: maintainer, help-wanted, needs-info, parked - Update examples to reference new label format Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> | 6 个月前 | |
Add LICENSE | 2 年前 | |
fix(devex): bootstrap canonical setup in linked worktrees | 29 天前 | |
docs: take operator pages off docs.omi.me Unlisted Mintlify MDX is still a public URL. Move runbooks, flags, invariants, and agent rules next to owning code, add docs/AGENTS.md as the site allow-list, and correct the live kill-switch contract after the JIT authority page leaves the site. Co-authored-by: Cursor <cursoragent@cursor.com> | 1 天前 | |
resolve merge conflicts from main rebase | 5 个月前 | |
fix: omi-lib Swift SDK resolves and builds on macOS (#11442) (#11490) The root Package.swift declared iOS-only platforms, so SwiftPM assumed macOS 10.13 and refused to resolve against AudioKit (macOS 11+). The package could not be built on a macOS host at all, and because it sits at the repo root it shadowed desktop/macos/Desktop for anyone running swift build from the root — with an AudioKit platform error that gave no hint the directory was wrong. Declare .macOS(.v14) (SwiftData parity with the existing iOS 17 floor) and drop the unused UIKit import in FriendManager.swift, the only remaining macOS-incompatible line. No UIKit symbol is referenced. Verified: - xcrun swift build --package-path . -> "Build complete!" (was: "the library 'omi-lib' requires macos 10.13, but depends on ... AudioKit which requires macos 11.0") - xcodebuild -scheme omi-lib -destination 'generic/platform=iOS' build -> "** BUILD SUCCEEDED **" (iOS path unchanged) Failure-Class: none | 18 天前 | |
feat(sdks): multi-lang device SDKs (protocol + STT + BLE) (#10227) * feat(sdks): add multi-lang device BLE protocol packages Share Omi GATT UUIDs and audio packet framing across TypeScript, Go, Rust, C++, and Dart under sdks/device. Keep full BLE stacks in the existing Python/Swift/React Native packages; wire Python constants to the same protocol doc. Failure-Class: none * feat(sdks): add multi-engine STT parity across device SDKs Expose deepgram, whisper, and parakeet engines with the same PCM16/16k contract on Python, Swift, React Native, TypeScript, Go, Rust, Dart, and C++ helpers. Feature-gate Whisper runners and optional BLE/STT stacks where native deps are platform-specific. Failure-Class: none * feat(sdks/device-rust): add btleplug-backed BLE feature Failure-Class: none * feat(sdks/device-cpp): add optional SimpleBLE client Failure-Class: none Optional OMI_DEVICE_BLE CMake gate (default OFF) adds scan/listen over SimpleBLE using Omi service/audio UUIDs. FetchContent falls back with a clear warning if SimpleBLE is unavailable. * feat(sdks/device-dart): add flutter_blue_plus BLE client Failure-Class: none Wire OmiBleClient + FlutterBluePlusOmiBle (scan/connect/listenAudio/listenPayload/disconnect) using existing protocol UUIDs and stripPacketHeader. Package now depends on Flutter SDK + flutter_blue_plus; pure protocol/STT unit tests still pass via dart test. Verification: cd sdks/device/dart && flutter pub get && dart test → All tests passed! * feat(sdks/device-go): add feature-gated BLE scan/listen Failure-Class: none * feat(sdks/device-ts): add optional noble BLE transport Failure-Class: none * feat(sdks/device-dart): port app GATT map onto flutter_blue_plus BLE Use main-app UUID constants and Omi audio/codec/battery flows with flutter_blue_plus for third-party Flutter apps. Add Python bleak high-level scan/listen API and document multi-lang BLE backends. Failure-Class: none * style(sdks): format device Dart/Python/Swift for CI Apply dart format (line-length 120), black, gofmt alignment, and swift-format so the Formatting gate passes. Failure-Class: none * chore(sdks): re-trigger CI after PR body invariant citation Failure-Class: none * fix(sdks): format device Dart for CI package-less dart Match dart format without package_config (CI only pub-gets app/). Failure-Class: none * fix(ci): green device SDK PR after main rebase Rebase onto main, restore Codemagic digests, format package-less Dart, black Python examples, and align desktop prod promotion policy with the collapsed Stable workflow from #10241. * fix(ci): match Codemagic digests and Dart line-length 120 Refresh approved Codemagic fixture digests to current codemagic.yaml (main fixture lag) and format device Dart with CI --line-length 120. * fix(sdks/device-ts): send Deepgram API key via token query param Stop assigning headers after WebSocket construction; standard browsers and many Node runtimes ignore it. Pass the key as a Deepgram-supported `token` query parameter so auth actually reaches the server. Failure-Class: none Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * fix(sdks/device-dart): send Deepgram API key via token query param web_socket_channel cannot carry arbitrary Authorization headers on all platforms, so the previous constructor accepted an apiKey but never sent it. Wire the key through the documented `token` query parameter. Failure-Class: none Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * docs(readme): remove duplicate MCP Server link Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * build(sdks/device-cpp): pin SimpleBLE via FetchContent with vendored override Replace the configure-time `git clone` with CMake FetchContent pinned to SimpleBLE v0.10.3 and add OMI_DEVICE_SIMPLEBLE_SOURCE_DIR so callers can opt into an explicit vendored dependency path. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * fix(sdks): authenticate Deepgram via headers in Dart and RN Use IOWebSocketChannel Authorization headers in the Dart device SDK instead of putting the API key in the WebSocket URL. Require createWebSocket on React Native so the default path cannot connect without auth headers. Failure-Class: none Co-authored-by: Cursor <cursoragent@cursor.com> * fix(sdks/ts): remove apiKey from Deepgram WS URL, add createWebSocket factory The token-in-URL query param leaks into server/proxy logs. Now: - deepgramWsUrl() returns token-free URL (sampleRate only) - deepgramWsUrlWithToken() preserved as deprecated fallback - createDeepgramTranscriber accepts optional createWebSocket factory (preferred path) or apiKey (deprecated, token-in-URL) - Tests cover both paths * fix(sdks/ts): require authenticated Deepgram transport Remove the token-in-URL fallback and require an injected authenticated WebSocket factory. Failure-Class: none * fix(sdks): deliver buffered Whisper transcript on stop Allow the terminal flush to emit its final transcript after stopping while keeping all subsequent PCM input disabled. Failure-Class: none --------- Co-authored-by: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com> | 1 个月前 | |
docs: add security policy (#8418) | 2 个月前 | |
fix(backend): make the meeting Chat receipt a durable reconciled projection (#11888) * fix(backend): make the meeting Chat receipt a durable reconciled projection A 28m40s Google Meet call produced a correct summary but no meeting-notes card in Chat. Detection, rotation and finalization all worked: the conversation carries conversation_role=meeting, conversation_finalization_reason=meeting_ended, and is_meeting_treatment_eligible returns True against the real record (duration 1720s, deduplicated speech 1719.8s). The receipt simply never arrived, and nothing in the system recorded why. The cause is structural rather than a single bad line. Meeting-treatment eligibility was recomputed at five call sites, against four different in-memory snapshots, at four different lifecycle moments, and the verdict was never persisted. #11836 was already one bug in that seam - a snapshot that answered before finalization and returned the default false. It fixed one caller. This was the next instance, and production could not attribute it either. Record the verdict once on the durable finalization job, with its reason and its measured inputs, and reconcile the receipt instead of emitting it as a one-shot event: - conversation_finalization_jobs becomes the receipt authority; the five call sites read the stored verdict rather than recomputing it. - One shared post-finalization receipt service covers both the cloud path and the local-segments (from-segments) path, so the receipt is written exactly once for either. - Intent persistence is distinguished from kernel materialization, which is the seam the receipt exists to close. - Reconciliation rides the existing five-minute finalization sweep - eligible and unmaterialized receipts are re-driven, idempotent through the existing capture:{conversation_id} continuity key. This also covers a v1 client, which deliberately leaves conversationLink intents pending and previously had nothing to retry it. - The obsolete persist_desktop_meeting_arrival adapter is removed; its test now proves the end-to-end contract instead - one eligible meeting yields exactly one conversationLink receipt, while ambient and rotation yield none. MEETING_RECEIPT_RECONCILER_ENABLED defaults false and is declared on both backend-listen and the Cloud Run backend service, which co-host this code path via POST /v1/conversations/{id}/reprocess. Client-side simplification and the duplicate local session rows are deliberately left as follow-ups, as are the separate detection workstreams (tier-2 mic detection, idle rotation) - those are detection problems and this is a delivery problem. Failure-Class: FC-durable-terminal-projection Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(backend): teach two hand-listed test fixtures about the new module and flag CI surfaced two lists that did not learn about this change. The conversation-events and conversation-search suites stub their dependencies through a hand-maintained dict of module names. routers/conversations.py now imports utils.conversations.meeting_receipt, which was absent from that dict, so both suites failed at collection with ModuleNotFoundError rather than any behavioural error. This is the drift FC-hand-listed-test-isolation-membership describes: omission is not an opt-out. The runtime-env validator builds a synthetic Cloud Run state to assert against the real manifest contract. That fixture did not declare MEETING_RECEIPT_RECONCILER_ENABLED, so the validator correctly reported it missing on cloud_run/backend - and the extra error also perturbed two unrelated assertions that count errors. Add a with_meeting_receipt_reconciler_env helper modelled on the existing with_conversation_notes_v2_env sibling, scoped to the backend service only, and wire it into the fixture composition chain. The flag itself was already correctly declared on both backend-listen and the Cloud Run backend service; no deployment configuration changed, and no assertion was weakened. Failure-Class: FC-hand-listed-test-isolation-membership Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com> | 12 天前 | |
fix(test): fix remaining AgentPill assertion after rebase | 1 个月前 | |
fix(release): keep candidates moving during Sentry outages Failure-Class: none | 8 天前 | |
Revert "Delete community-plugin-stats.json" | 3 个月前 | |
fix(desktop): keep Memory dropdown pills opaque Give the stacked destination pills a solid neutral Omi surface, restrained border, and shadow so page content cannot show through the hover menu. Verification: MemoryGraphRevisitTests (11 passing); live open-dropdown capture in omi-qa-main; design QA comparison passed. Failure-Class: none | 1 个月前 | |
feat: add local dev harness lifecycle commands | 2 个月前 | |
fix(backend): make the unsubscribe link work, and stop counting listen stubs Four defects found by an adversarial review of the original PR, each of which would have shipped silently. **The unsubscribe link went to the wrong service.** `unsubscribe_url` built on `share_base_url()` — the conversation-share web origin (`h.omi.me`) — while `/email/unsubscribe` is a FastAPI route on the API. Every link in every message would have 404'd, and the RFC 8058 `List-Unsubscribe` header with it, because it carries the same URL. It now builds on `BASE_API_URL` and raises when that is unset: an unsolicited email with no working opt-out must not be sent at all. **GET performed the opt-out.** Outlook Safe Links and comparable gateways fetch every URL in a message before the recipient sees it, so a writing GET would have unsubscribed people who never clicked — suppressing real recipients and inflating the unsubscribe rate the pre-registration names as its stop-for-harm guardrail, until it measured scanner traffic instead of harm. GET now renders a confirm form and writes nothing; POST is the only writer, which is also why RFC 8058 one-click is a POST, so mail clients stay one-click. **"Has the user come back?" counted conversation documents, not conversations.** The desktop listen socket writes an `in_progress` stub on every session start and reconnect, so a Mac that is merely switched on manufactures documents with fresh `created_at` values and no content. That is the same launch-at-login contamination that disqualified `last_active_at`, re-imported through the value signal chosen to avoid it — it would have left the experiment enrolling only users whose machines were off. Both conversation probes now require `discarded == False, status == 'completed'`, matching what `get_conversations` counts by default. **A failed send was never retried.** The run loop returned early on `not newly_enrolled`, which conflates the analysis lock with the send-once lock. A treatment user whose first attempt died after enrolling — provider blip, killed job, released claim after a definitive rejection — was skipped by every later run and never mailed, while still counting as treated. The claim ledger is the send-once lock and always was; the loop now relies on it. Also wires the job for deployment (runtime image registration, both deploy workflows, runtime env with the API origin per environment) — it previously had a Dockerfile and a scheduler script but no path to production. Requires two Secret Manager entries before any deploy: LIFECYCLE_EMAIL_SIGNING_SECRET (on the job *and* the API — the job mints unsubscribe tokens, the API verifies them) and RESEND_API_KEY on the job. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> | 1 天前 | |
refactor(infra): simplify GCP/Firebase deploy control plane Decompose the monolithic runtime env manifest, unify GKE config rendering, extract shared backend deploy orchestration into a composite action, and remove dead Firestore rules / duplicate index provisioning paths. Co-authored-by: Cursor <cursoragent@cursor.com> | 29 天前 | |
fix(security): resolve Dependabot security vulnerabilities across workspace (#10875) * fix(backend): update vulnerable python dependencies to patch ranges (~=) * fix(desktop): update vulnerable dependencies in desktop apps to patch ranges (~) * fix(web): update vulnerable dependencies in web applications to patch ranges (~) * fix(sdks): update vulnerable dependencies in react-native sdk and example to patch ranges (~) * fix(mcp): update vulnerable python dependencies in mcp server to patch ranges (~=) * fix(plugins): update vulnerable python dependencies in plugins to patch ranges (~=) * fix(docs): update vulnerable dependencies in docs to patch ranges (~) * fix(omiGlass): update vulnerable dependencies in omiGlass to patch ranges (~) * fix(root): update vulnerable dependencies in root package to patch ranges (~) * fix(windows): apply pnpm security overrides * fix(windows): align electron-builder package family Failure-Class: none Verification: pnpm install --frozen-lockfile; pnpm exec electron-builder install-app-deps; pnpm run typecheck; pnpm run lint; git diff --check. * fix(deps): pin runtime requirements to locked versions Make PR-updated Python runtime requirements exact pins matching their committed backend locks; make MCP's lock-backed constraint explicit and remove its unresolved constraint. Validation: backend/scripts/sync-python-deps.sh; backend/test.sh; mcp uv lock --locked; mcp pytest; locked npm/pnpm resolutions; make preflight. Failure-Class: none | 1 个月前 | |
feat: add JIT knowledge ledger foundation and guarded adoption (#12084) * feat: add JIT knowledge ledger foundation * chore: refresh integration OpenAPI contract * fix: make trigger evaluation release-safe Failure-Class: none * fix: preserve lifecycle semantics in ledger apply Failure-Class: none * feat: adopt guarded JIT knowledge surfaces Route the agent preference writer through the intent-backed ledger, register a privacy-filtered entity timeline tool, render optional evidence on Windows, and add a base-ref-protected Gate F legacy-surface ratchet. Failure-Class: none * feat: add progressive JIT knowledge reads Register owner-scoped current-ledger search and explicit playbook hydration, with pre-limit semantic filtering and bounded outputs. Add a content-free planner/resume migration fixture without claiming canonical transaction completion.\n\nValidation: 141 focused backend tests passed; backend typecheck reported 0 errors; repository preflight passed 120 checks. * feat: render chat evidence on web Render bounded, fail-soft conversation evidence after authoritative answers in both web chat entry points. Unsupported, future, duplicate, and raw failure details remain inert.\n\nValidation: 337 web tests passed; web typecheck, oxlint, and Prettier passed; repository preflight passed 120 checks. * feat: require intent-backed ledger search results Apply the intent-backed requirement at the final merged canonical/history filter, with a passive historical-row regression case.\n\nValidation: 54 focused backend tests passed. * test: keep agent tool isolation stubs current * feat: gate JIT conversation retrieval * fix: make entity timeline scans deterministic Failure-Class: none * fix: honor rejected ledger projections Failure-Class: none * feat: render inert screen evidence on web * fix: reuse canonical review projection Failure-Class: none * fix(web): await recap context effect Failure-Class: none * test: amortize preference tool isolation load Failure-Class: none * feat(app): add knowledge ledger review surface Failure-Class: none * feat(macos): use canonical ledger prompt projection Failure-Class: none * test(memory): classify legacy surface inventory roles Failure-Class: none * fix(app): preserve ledger history completeness state Failure-Class: none * feat(macos): preserve canonical ledger mirror metadata Failure-Class: none * fix(app): match canonical ledger ordering Failure-Class: none * test(api): prove ledger client schema parity Failure-Class: none * feat(memory): expose bounded ledger history Failure-Class: none * chore(api): generate ledger history clients Failure-Class: none * feat(retrieval): add bounded card participants Failure-Class: none * feat(macos): project ledger trigger watchlist Failure-Class: none * fix(clients): fail closed on ledger authority Failure-Class: none * feat(macos): expose bounded trigger snapshot Failure-Class: none * fix(memory): keep closed history read only Failure-Class: none * feat(app): disclose partial ledger history Failure-Class: none * test(macos): cover ledger trigger bridge Failure-Class: none * fix(app): use neutral ledger accents Failure-Class: none * chore(api): declare ledger history route policy Failure-Class: none * test(macos): remove unsafe JSON fixture unwraps Failure-Class: none * fix(memory): satisfy typed history boundary Failure-Class: none * fix(macos): require prompt snapshot authority Failure-Class: none * test(memory): prove ledger migration on emulator Failure-Class: none * feat(retrieval): emit bounded screen evidence Failure-Class: none * test(memory): classify maintenance retirement readiness Failure-Class: none * feat(macos): adapt Rewind metadata for triggers Failure-Class: none * test(retrieval): align screen timestamp contract Failure-Class: none * feat(memory): correct ledger facts by amendment Failure-Class: none * test(memory): prove ledger correction on emulator Failure-Class: none * feat(macos): harden local trigger observations Failure-Class: none * feat(agent): search bounded historical facts Failure-Class: none * test(macos): cover trigger observation adapter * fix(memory): gate historical fact retrieval * feat(memory): add gated JIT retrieval strategy * test(memory): prove mixed-version JIT runtime parity * chore(memory): keep JIT gate exports type-safe * refactor(memory): isolate JIT prompt contract * fix(conversations): round-trip owner-scoped references Accept the conversation:<id> references emitted by JIT result cards while retaining strict UUID-only bare IDs and share links. Restrict machine IDs to a bounded safe alphabet so evidence suffixes and path-like values fail closed. Failure-Class: none * test(memory): join JIT citations to evidence envelope * fix(retrieval): enforce JIT conversation search budget Cap JIT summary searches per request and bound database hydration to the projection limit before reads. Preserve the legacy path when JIT is disabled. Failure-Class: FC-unbounded-user-collection-in-prompt * fix(memory): keep JIT retrieval request scoped * test(macos): prove future JIT evidence stays inert * fix(memory): keep JIT card citations request-global Failure-Class: new * fix(retrieval): separate JIT hydration from search Treat gated owner-scoped references as exact hydration without searching transcript text for the reference. Charge every JIT candidate search to the shared four-search request budget, including snippet-bearing requests, while keeping exact hydration free and preserving released JIT-off UUID/share-link behavior.\n\nVerified:\n- cd backend && ./.venv/bin/python -m pytest tests/unit/test_conversation_jit_processing.py tests/unit/test_conversation_exact_reference_search.py -q (58 passed)\n- cd backend && uvx --from pyright==1.1.403 pyright -p pyrightconfig.json --pythonpath .venv/bin/python (0 errors)\n- git diff --check\n\nFailure-Class: FC-unbounded-user-collection-in-prompt * fix(memory): keep repeated JIT cards index-safe * fix(retrieval): satisfy JIT card type contract * fix(retrieval): hydrate collected JIT cards * test(app): preserve answers during delayed evidence requests * test(app): exercise production evidence composition * feat(memories): restore superseded ledger facts * fix(memories): reconcile reverted ledger facts * feat(memories): append reverted ledger facts * feat(memories): synchronize revert client contract * fix(memory): name ledger revert identity * fix(memories): type and enlarge revert controls * fix(memories): fence revert retries and refreshes * fix(memories): fence ledger revert authority * test(memory): count ledger revert rate limit * feat: expose agent-controlled historical facts * feat: reopen standalone ledger facts * feat: add fail-closed JIT QA bundle routing * feat: add safe local JIT QA backend stack * fix: harden isolated JIT QA stack * feat: add explicit multi-source entity timeline * feat(backend): add JIT rollout authority * feat(backend): fence every proactive paid boundary * fix(backend): release proactive quota on cancellation Release the reserved proactive quota exactly once when cancellation interrupts paid-boundary refresh or a provider retry, then re-raise cancellation without emitting retry telemetry. Add deterministic regression coverage for both cancellation points. Failure-Class: FC-proactive-quota-cancellation | new * fix(backend): make proactive quota cancellation safe Detach in-flight Redis reservations on request cancellation and release only admitted slots once they settle. Move direct-provider fallback telemetry behind the fresh paid-boundary rollout check so late kill or unknown decisions cannot report false recovery.\n\nFailure-Class: FC-proactive-quota-cancellation | new * fix(backend): preserve quota compensation during shutdown Keep late Redis reservation compensators outside the ordinary cancellable background-task drain. Desktop and main application shutdown paths now wait for these critical compensators before cancelling ordinary work, with deterministic blocked-thread and lifecycle-order regressions.\n\nFailure-Class: FC-proactive-quota-cancellation | new * fix(backend): use expiring proactive quota leases * fix(backend): make quota finalization clock-safe * fix(backend): isolate jit rollout control plane * fix(backend): close jit control plane safely * fix(backend): emit retry recovery after quota commit * test(backend): keep rollout app contract fast * feat(jit): add guarded proactivity and first-open policies * chore(desktop): mark jit policy as internal * test(desktop): cover jit proactivity policy flow * feat(backend): wire durable JIT first-open processing * feat(desktop): fence JIT proactivity runtime admission * feat: activate authoritative JIT proactivity runtime * fix: harden JIT proactivity authority * fix: close proactive runtime authority gaps * fix(jit): make first-open effects resumable * fix(jit): fence outstanding first-open work * fix(jit): resume app usage receipts * fix(jit): make app usage retries no-op Failure-Class: none * fix(jit): allow completed usage after app deletion Failure-Class: none * fix(jit): register first-open folder query Failure-Class: none * Fix first-open import isolation * feat(memory): govern ledger slots and prompt winners * feat(macos): stage guarded ledger prompt adoption * feat(jit): adopt authoritative ledger prompts on macOS * fix(jit): close ledger adoption authority leaks * fix(jit): reauthorize every ledger migration write * fix(jit): fence ledger cutover publication * fix: keep ledger prompt rollback reversible * feat(jit): add guarded frame request retention contracts * fix(jit): close frame retention authority and evidence lifecycle * fix(jit): make frame retention retries and cleanup durable * fix(jit): make frame evidence recovery and retention complete * fix(jit): close frame retention recovery gaps * Harden temporary frame retention and deployment * fix: harden JIT frame retention and consumption * fix: close JIT frame lifecycle recovery gaps * fix: unify JIT frame authority and retention Failure-Class: FC-split-mutation-authority * docs: keep frame retention guidance lean * fix: retire duplicate frame flag bindings Failure-Class: FC-split-mutation-authority * fix: register frame keyframe queries Failure-Class: FC-split-mutation-authority * fix: serialize frame retention deploys Failure-Class: FC-split-mutation-authority * test: cover frame pixel deletion ordering * style: format cumulative Dart changes * fix(app): retain permanent conversation photo fetches * fix: bound frame vision retention and authority * fix: drain terminal frame request metadata * chore: record internal ledger adoption change * feat(memory): add dark daily sweep authority * feat(memory): harden daily sweep fences and runtime seam * feat(memory): reconcile existing standing triggers in sweep adapter * fix(memory): harden daily sweep recovery and source fences * fix(memory): close daily sweep source producers * fix(memory): close daily sweep review findings * Add dark daily memory sweep authority and recovery * fix(memory): harden daily sweep rejection repairs * test(listen): stub onboarding admission in bootstrap regression The daily sweep PR fences onboarding mode behind the server-owned backend admission (get_backend_onboarding_admission), so the bootstrap regression test now simulates an admitted session instead of failing closed on a real Firestore read. Verification: focused test passes in 1.64s (previously failed after a 4m27s Firestore timeout); full test_listen_runtime_regressions.py + test_onboarding_question_start.py: 26 passed; black --check clean. * fix(memory): close daily sweep rollout and retry cursors * fix(memory): isolate daily sweep lifecycle and retry fairness * Harden daily sweep admission and completed-day staging * fix daily memory sweep reliability boundaries * preserve daily sweep invocation tombstones * close daily sweep invocation lifecycle fences * fix: keep daily sweep lifecycle cleanup active * fix: acquire ledger snapshot client off event loop * fix(memory): preserve migration tier fence without legacy growth * test(memory): prove legacy adjudication race fences * fix(dev): allow bounded ADC readiness refresh * test: keep ledger prepush deterministic * test(memory): register prompt receipt control path * fix(memory): fence ledger writer transitions * feat(backend): preserve closed ledger history in export * feat(memory): define ledger query semantics * fix(backend): fence trigger snapshots on final authority * fix(backend): bypass stale coalesced JIT refreshes * feat(macos): mirror bounded memory evidence Decode generated v3 evidence into a domain mirror, persist canonical bounded JSON through the memory cache, and preserve it across compatibility sync and older-local conflicts. Invalid, future-shaped, oversized, and over-count payloads fail closed without hiding memory text or granting prompt authority. Tests: xcrun swift test --package-path Desktop --filter ServerMemoryV17DecodingTests Tests: xcrun swift test --package-path Desktop --filter MemoryLedgerMirrorTests Tests: python3 scripts/check_desktop_test_quality.py Failure-Class: none * fix(macos): fence and classify memory evidence Keep generated memory fields independent from malformed evidence, distinguish absent valid and invalid evidence states, preserve prior evidence on invalid payloads, and gate replacements on a monotonic server timestamp so stale active evidence cannot resurrect redacted rows. Cover populated-table migration upgrades. Tests: xcrun swift test --package-path Desktop --filter ServerMemoryV17DecodingTests Tests: xcrun swift test --package-path Desktop --filter MemoryLedgerMirrorTests Tests: python3 scripts/check_desktop_test_quality.py Failure-Class: none * fix(macos): preserve evidence fences and scrub redactions Advance evidence revisions for identical valid payloads, fence stale active responses after a local edit, and remove artifact/device pointers from redacted evidence before canonical persistence. Tests: xcrun swift test --package-path Desktop --filter ServerMemoryV17DecodingTests Tests: xcrun swift test --package-path Desktop --filter MemoryLedgerMirrorTests Tests: python3 scripts/check_desktop_test_quality.py Failure-Class: none * chore(macos): record ledger evidence mirror * feat(macos): deep-link local evidence cards to Rewind * fix(macos): fence Rewind frame evidence version * fix(macos): validate Rewind evidence card availability * fix(macos): bind task detail Rewind navigation to local leases * fix(macos): fence Rewind citation owner handoff * chore(macos): register Rewind evidence deep links * test(macos): cover Rewind evidence navigation * feat(desktop): evaluate JIT trigger watchlists locally * feat(desktop): wire authoritative JIT trigger runtime * feat(desktop): bind JIT claims to snapshot authority * fix(desktop): revalidate trigger authority at execution * fix(desktop): keep JIT execution leases live * test(memory): bind standalone reopen to direct-user writer * fix: make JIT QA sign-in self-contained Failure-Class: new Verification: bash desktop/macos/tests/test-jit-qa-target.sh; bash desktop/macos/tests/test-yolo-dev-backend.sh; repaired named-bundle Google sign-in reached authenticated onboarding. * feat(memory): complete JIT policy and native Windows parity * docs(backend): keep service map within context budget * test(macos): cover JIT client and staging flows * chore(backend): declare JIT mirror route policy * fix(backend): use strict Firestore boundary for JIT admission Failure-Class: FC-malformed-doc-read * chore(quality): register malformed-document guard surface * fix(backend): fail closed on malformed JIT authority Failure-Class: FC-malformed-doc-read * refactor(backend): name JIT workflow boundary results * test: repair JIT CI contracts * fix(backend): preserve ledger query exports Retain the explicit same-name re-exports consumed by tests and downstream callers while satisfying the enforced Pyright unused-import boundary after the main rebase. Failure-Class: none * test(backend): isolate gateway setup timing Failure-Class: none * style(memory): format direct-user evidence path Failure-Class: none * test(agent): isolate ACP process-group fallback Failure-Class: none * fix(dev-harness): preserve ownership markers in narrow CI * test(jit): refresh emulator fixtures for current contracts * test(jit): orchestrate local rollout dogfood * test(jit): harden local dogfood authority * fix(dev-harness): install PostHog for CI tests * fix(chat): project server JIT rollout into retrieval Resolve the backend-owned PostHog decision inside the bounded agent setup path and pass only its boolean result to prompt/tool configuration. Unknown or failed authority remains on the released legacy path, while callers cannot self-enroll through configurable input.\n\nVerification: backend/.venv/bin/python -m pytest -q backend/tests/unit/test_chat_async_offload.py backend/tests/unit/test_atomicity_lifecycle_regressions.py (41 passed)\n\nFailure-Class: new * fix(memory): preserve preference writer compatibility Select the agent preference write path from the canonical per-user writer control. Default compatibility mode retains the released MemoryService payload and receipt behavior; ledger mode keeps the retry-stable ledger write, and transition states fail closed.\n\nVerification: backend/.venv/bin/python -m pytest -q backend/tests/unit/test_chat_async_offload.py backend/tests/unit/test_atomicity_lifecycle_regressions.py (41 passed)\n\nFailure-Class: FC-split-mutation-authority * fix(jit): separate migration rollout authority Keep staged JIT chat and proactive exposure independent from legacy-row migration and writer cutover. Migration now requires its own default-off PostHog flag and still rechecks the shared kill switch at every mutation and publication boundary. Repair the isolated conversation-JIT fixture for main's chat-scope import. Verification: 217 focused JIT, chat-scope, migration, and lifecycle tests passed; 28 conversation-JIT fixture tests passed; independent Sol review accepted the split for QA-only dev rollout. Failure-Class: FC-split-mutation-authority * fix(photos): preserve retained image retrieval Treat an empty legacy inline marker as absent when permanent storage is authoritative, while malformed non-empty inline payloads still fail closed. Route live and retained thumbnails through the storage-aware image loader and preserve the conversation identity through the full-screen viewer.\n\nVerification: backend data-export tests 32 passed; Flutter photo-viewer tests 5 passed; focused Dart analysis clean; independent Sol review found and verified the viewer identity repair.\n\nFailure-Class: none * fix(memory): keep disabled daily sweep dark Resolve the backend-owned authority before inventory and require its literal true decision before any UID discovery, registry, cleanup, scheduler, model, or commit work. Missing, malformed, throwing, disabled, and kill-switched authority now exits without touching user data; enabled behavior is preserved.\n\nVerification: 60 focused daily-sweep job, scheduler, and inventory tests passed; independent Sol review accepted the fail-closed gate.\n\nFailure-Class: FC-split-mutation-authority * fix(jit): satisfy fail-closed type contracts * test(backend): admit full runtime contract checks * style(backend): format conversation bound test * test(backend): keep conversation router isolation current * test(backend): admit export boundary duration * fix(macos): persist failed chat turn notice Failure-Class: none * fix(macos): repair JIT rollout admission contracts Failure-Class: none * fix(windows): treat JIT screen evidence as untrusted Failure-Class: none * fix(backend): preserve explicit app failure contract Failure-Class: none * fix(app): finish photo viewer consolidation * fix(backend): make provider writes lock-free against the deletion gate The account-wide legal-hold deletion gate wrapped every GCS upload and Pinecone/Typesense upsert in an exclusive per-uid Firestore mutex with no lease: concurrent same-account writes hard-failed (dropped audio, lost vectors) and a crash between acquire and finish blocked the account's gated operations forever, with no janitor. Provider writes now use a lock-free fence that refuses only during account deletion or a live destructive operation; destructive kinds keep exclusive ownership, an abandoned gate self-expires after six hours, and releasing a gate on the failure path can no longer mask the original error. Failure-Class: none Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(backend): issue onboarding admission at socket connect The completed-onboarding early exit returned False from an Optional[str] function; the listen runtime derives admission via 'is not None', so users who had already completed onboarding were admitted with a fabricated session id — the exact provenance forgery the admission exists to prevent. Separately, the 20-minute admission TTL was anchored to the app-launch state read, so a user reaching the speech-profile step late (or any client that never calls the state endpoint) silently lost onboarding questions and is_user tagging. The bootstrap now issues or refreshes the admission from the durable account state at connect time; completed accounts still can never re-enter, and issuing stays best-effort with the read failing closed. Failure-Class: none Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(backend): keep the released proactivity lane open for legacy clients Gating /v1/desktop/proactivity/completions on the JIT cohort returned 403 to every non-admitted user — which is the entire deployed desktop fleet on deploy day, since shipped clients poll this route continuously and treat 403 as a plain error. Context-bucket extraction and the director would have died fleet-wide, dark cohort or not, and any environment without a PostHog key (local, self-host) would have lost the lane entirely. The route returns to merge-base admission semantics (tier quotas only); JIT admission remains enforced on the JIT reservation routes, and retiring this lane stays a later explicit operation after clients migrate. Failure-Class: none Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(backend): withhold JIT tools and history reads outside the rollout Five new tools (search_knowledge, search_historical_facts, read_playbook, get_entity_timeline, look_at_frame) sat unconditionally in CORE_TOOLS, so every legacy chat request carried their schemas and the model burned tool budget on 'no entries found' answers. They are now filtered per request off the same resolved rollout boolean that gates the JIT prompt appendix. The memories-tab ledger-history endpoint likewise answered every user with a bounded 501-row provider scan that can only ever be empty outside the rollout; it now returns empty without the scan for non-admitted (and unknown/error) states. Failure-Class: none Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(backend): bound rollout control-plane cost and confine sync resolution Synchronous callers resolved rollout flags via per-call asyncio.run against the shared provider singleton, crossing event loops: awaiting a Task attached to another loop raises, a timed-out asyncio.run strands a coalescer entry that then serves stale UNKNOWN forever, and the LRU cache was mutated from multiple threads. Sync resolution now runs on one long-lived control-loop thread with its own authority instance. Unknown snapshots gain a 5-second negative cache — UNKNOWN can never authorize work, and without it a fleet whose flags are simply absent pays one uncached PostHog call per conversation finalization. The screen-sync loop drops its force_refresh (one uncached decide per device per minute fleet-wide) and moves to its own rate bucket so two Macs' background sync can no longer starve conversation photo reads out of the shared 120/hour frame-requests bucket. The first-open policy's kill-switch telemetry label also reported str(Enum) instead of the value and could never match. Failure-Class: none Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(backend): skip eager extraction under a non-compatibility writer mode A ledger-cutover user still ran the full L1 extraction model call at finalization, after which writer admission refused the compatibility write — the conflict retried, exhausted, and failed the entire finalization for every conversation, with the model spend already paid. Extraction now checks the canonical writer mode first and skips when the daily sweep owns memory formation; only a positively-read non-compatibility mode skips, so any control-state read failure preserves the legacy eager path. Failure-Class: none Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(backend): export tolerates byte-less legacy photo rows A conversation photo row carrying the legacy empty inline marker and no storage reference failed the whole portability export forever, though it holds no durable image anywhere — there is nothing to omit. Such rows now export as metadata with a content-free gap reason. Frame requests in a retained state keep the fail-closed contract via an explicit require_bytes parameter. Failure-Class: none Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(windows): harden JIT delivery, admission, and bootstrap boundaries Five verified defects: (1) the exclusive notification delivery slot leaked on any throw between reservation and commit — one SQLite hiccup during a JIT turn permanently silenced every proactive lane; the span is now try/finally-guarded and stale slots expire after ten minutes. (2) The ambient lane interpolated the raw window title into a tool-capable agent prompt; the turn now carries only the opaque context handle plus a sanitized executable name, framed as untrusted data like the nano-triage lane. (3) Google Calendar was fetched every ~60s before admission, so non-cohort users with Google connected paid ~1,440 reads a day for a refused feature; observation now gates calendar evidence on the cached authority. (4) Rollout-authority errors reset the cache and retried every frame (~1 req/s offline, forever); failures now back off from 30s to 10 minutes. (5) An unguarded JIT schema exec inside the shared database open could abort local storage for all features; the mirror bootstrap is now isolated, keeps the host-facing tables alive, and JIT stays inert when unavailable. Also re-checks the control-plane owner before committing the toast so an account switch mid-turn cannot show the previous owner's advice. Failure-Class: none Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(macos): restore screen provenance, guard migrations, fence chat turns Four verified defects: (1) every pre-existing screen-derived task lost its 'Screen context / Open Rewind' source row because the new evidence policy dropped any provenance that is not rewind_frame.v1; the merge-base fallback row is restored for capture.v2/legacy refs (a test flipped to match the regression is restored to its merge-base assertions). (2) RewindDatabase published its pool before migrating, latching a failed migration into a permanent false-initialized state, and three unguarded ALTER TABLE memories migrations died with duplicate-column on machines that ran earlier builds of this branch; migration now precedes publication and the ALTERs/CREATEs are existence-guarded. (3) EventKit was queried on every context visit before the flags check; non-admitted owners now build no observation inputs. (4) A failed chat turn's reconstructed notice could be appended into a different conversation's transcript when the user switched sessions or cleared chat mid-flight; both transcript resets now revoke the active turn like selectApp already did. The pre-terminalized discard class (user Stop/watchdog) still drops the durable notice on relaunch — pinned by a characterization test in agent/tests/conversation-journal.test.ts with the least-invasive fix described there. Failure-Class: none Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(testing): resolve firebase-tools from the checked-in dependency npx --prefix resolves the package bin against the current directory on some npm versions, and the admission runner deliberately launches from an isolated temp dir (firebase writes debug logs to cwd) — surfacing as 'sh: firebase: command not found' on hosts without brew node@22. Prefer the vendored node_modules binary when it matches the pin; npx remains the fallback. Failure-Class: none Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor(backend): keep one eager-extraction call site for the surface ratchet Failure-Class: none Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor(backend): gate eager extraction at the public boundary The writer-mode skip moves from _extract_memories_inner to extract_memories: the replace-policy contract test pins the inner helper to exactly the canonical replacement path, and the public boundary is the better seam anyway — a sweep-owned user now skips parity capture and usage tracking along with the model call. Failure-Class: none Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test(listen): stub onboarding admission issuance in bootstrap regression The connect-time ensure call landed in a harness that only stubbed the read, so the bootstrap test paid an extra real-module exception path and grazed the 0.30s fast-unit CPU budget under fanout load. Stub the issuance like the read. Failure-Class: none Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test(listen): allowlist the bootstrap regression's CPU budget The full listen-runtime bootstrap test measures exactly at the 0.30s fast-unit CPU budget under a saturated pre-push fanout (CPU inflates ~2x there per the guard's own notes) while passing comfortably alone. It exercises deliberately heavyweight machinery; record it as an intentional exception rather than trimming the coverage. Failure-Class: none Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(backend): keep list(CORE_TOOLS) literal through JIT tool gating The JIT-only tool filter replaced the list(CORE_TOOLS) assignment with an inline comprehension, which broke the prompt-cache structural invariant (test_prompt_cache_optimization.py::test_core_tools_used_in_both_functions). Restore the list(CORE_TOOLS) copy and apply the JIT-only filter as a conditional pass, preserving rollout semantics and tool order. * feat(jit): drop automatic goal updates from the JIT featureset Product decision (David, 2026-08-26): goals change only through explicit user action for JIT-admitted conversations. Goal progress is no longer a first-open obligation — the effect is removed from FIRST_OPEN_EFFECTS and the worker, and the policy plan can no longer express deferring it. Legacy obligations carrying a pending goal_progress row are normalized away and complete on the remaining two effects. Non-JIT (legacy eager) conversations keep today's automatic goal updates unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(sweep): one summary-spine agent pass per day, with folder backstop Replaces the per-conversation transcript extractor in the completed-day producer with a single two-phase agent run: the whole day's conversation summaries go in as one bounded spine (200 conversations / 120k chars — effectively unreachable, so heavy days no longer stall the cursor), and the agent may request up to 8 raw transcript excerpts (8k chars each) to verify specifics before finalizing. At most two provider calls per user per day, both inside the existing at-most-once invocation fence; the staged page carries the memory candidates AND folder assignments for the day's unopened, unfiled conversations, applied idempotently (first-open or user assignment always wins). Memories must cite their source conversations; uncited output is dropped. The cost gate becomes a worst-case ceiling checked before any call. The onboarding cold-start channel keeps per-conversation transcript extraction unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(sweep): harden the daily agent prompts from a real-data lab pass Iterated on one real heavy day (26 conversations) with strong- and weak-model stand-ins, an adversarial judge, and hand-verified transcript ground truths. Rules added, each pinned to an observed failure: actor binding in active voice with a personal-attribute gate (a discussed or recommended topic is never someone's attribute; judgments about named people are stored as assessments); decision-state basis labels binding the verb (decided/proposed/observed, discussed-no-outcome dropped); salience ordering (money, metrics, named-party intent, identity, and durable decisions before any operational fact; one fact per memory); never guessing the direction of an invitation/offer/commitment (verify or drop); and no deferring the whole answer to verification. The agent output schema gains a 'basis' field. The memories QoS call-site inventories now count the daily-sweep agent's call site (3 -> 4). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(sweep): tune the daily agent prompts against the real memories model Ran the assembled prompts against gpt-5.6-luna (the real 'memories' route model) on the same real day. Three refinements from observed behavior: the basis label no longer leaks into memory text (metrics read as metrics, not 'David observed that…'); the never-guess-direction trigger is mechanical (passive/verbless summary phrasing or 'Speaker' as the actor forces a transcript_request — luna confidently inverted 'Tim: Invited to New York' until this; with it, phase B verifies and corrects to the true direction), hedging is itself a request signal, and nothing high-salience may be silently dropped; and a rich-day yield anchor (8-16 memories for 15+ conversations) counters the model's over-pruning without inviting padding. Final real-model run: 11 true memories + 2 legitimate verification requests, zero fabrications, ~22k tokens (~2 calls) for a 26-conversation day. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(sweep): profile-maintaining slots, ledger lookups, cache-ready prompts The daily agent now sees the user's current profile (the same get_prompt_memories seam chat uses — the ledger render for migrated users), may run up to 4 owner-scoped prior-memory keyword lookups (provider fail-soft; hits re-read through the canonical store before disclosure) to dedup and supersede, and may name a slot for standing attributes — an occupied slot becomes an amend through the existing canonical occupancy check, so the daily run maintains the rendered profile with no second write path. Both phase prompts share a byte-identical prefix (pinned by a test) and pass a per-user prompt_cache_key through get_llm; measured against gpt-5.6-luna the provider cache is exact-match rather than prefix-based today, so this is future-proofing rather than present savings. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(sweep): type the memory-searcher seam for the pyright contract CI's authoritative typecheck rejected the untyped lookup seam (memories.py: list(Any or [])). The searcher is now Optional[Callable[[str], Sequence[str]]] and results are built through a typed comprehension; behavior unchanged (absent or failing searcher still degrades to an empty result block). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix: repair four main-inherited CI breakages after sync origin/main is currently red on its own tip; syncing it into this PR inherits the breakage, so the fixes ride here: - subscription.py: drop the unused get_byok_keys import (pyright reportUnusedImport fails the Backend unit suite). - AppState+Transcription.swift: explicit self for alertPresenter inside the escaping showAlert completion (strict-concurrency compile error in all three Desktop Swift lanes, shipped red on main by d49f978512). - AppState+Permissions.swift: pinned swift-format drift from the same main commit (desktop-swift-format-lint). - web/app/bun.lock: add the prettier + prettier-plugin-tailwindcss entries 64db30c791 pinned in package.json without updating the lockfile (frozen install fails web-app-checks). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(sweep): close the second review round's findings Three parallel adversarial reviews over the post-takeover additions: - Clamp every model-controlled phase-B input (draft memories, request reasons, lookup queries/results) and add the clamped worst case to the pre-call cost ceiling, which previously under-estimated phase B. - Attest an empty consumed day when the staged page carries an older stage schema version instead of stalling the cursor forever on every deploy-boundary schema bump. - Make the folder backstop's unfiled check and write share one transaction so a concurrent first-open/user assignment always wins. - Let equal-rank sweep candidates amend sweep-authored slot occupants: the profile-maintenance path froze after a slot's first write. User statements still always win; slotless subject matches still dedup. - Neutralize ``` fences in summaries/excerpts/lookup results, and mark raw-transcript fallback rows '(unstructured transcript excerpt)' with a prompt rule refusing slots/personal attributes from them without transcript verification (test pins the marker to the rule). - Remove the dead first-open goal-authority threading left by the goals removal, and update the stale jit-first-open-runtime doc. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix: repair three more main-inherited breakages All shipped red on main and only surfaced once earlier failures were cleared: - AppState.swift: move the alertPresenter default out of the stored property initializer — Xcode 16.4's SILGen segfaults (signal 11) emitting it, which failed all three Desktop Swift lanes even after the explicit-self fix. - test_byok_security.py: main's BYOK rewrite (d0e3a4eb3a, 1da8880175) changed request_has_llm_byok_key to per-provider enrollment checks and made partial headers fail closed, but left the tests targeting the old get_byok_keys()-based lenient contract (masked on main because pyright failed before pytest ran). The tests now assert the shipped strict contract their own docstrings already describe. - subscription.py: pinned-black formatting for the BYOK fallback expression (the Formatting lane rejects the file as main wrote it). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(tests): stub the chat-agent gateway route pin in the chat router harness Main's a6988be309 made routers.chat import CHAT_AGENT_ROUTE_DIRECT / get_chat_agent_route from utils.llm.gateway_client, but the chat-router test harness (and test_chat_file_upload_unsupported's local override) stub utils.llm.gateway_client without those symbols, so every suite that loads the real router failed at import — masked on main because pyright fails its Backend unit suite before pytest runs. Ninth main-inherited repair in this sync. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(tests): teach test_chat_quota's utils.byok stub the rewritten import surface utils/subscription.py now imports get_byok_uid and get_cached_byok_state (main's BYOK rewrite); the module-scoped utils.byok fake predates them, so reloading subscription under the fake raised ImportError at setup — and the polluted process took test_chat_openapi_operation_ids and test_desktop_screen_crisp down with it in CI's batched run (all three pass standalone). Tenth main-inherited repair, same pyright-masked pattern. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(tests): update three more suites for main's BYOK/gateway import surface Same pyright-masked pattern as the harness and test_chat_quota repairs: - test_desktop_transcribe stubbed utils.llm as a non-package, so routers.chat's new utils.llm.gateway_client import could not resolve (50 failures); the submodule is now in its stub list. - test_paywall_reconnect_gate's BYOK escape-hatch tests never set the request uid context that the enrollment-verifying rewrite requires (middleware sets it in production); they now do, and teardown clears it. - test_chat_session_app_identity's enforce_chat_quota stub rejected the new required_llm_provider keyword. All three suites pass locally (69 + 35 + 6). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(tests): enroll fingerprints in the desktop BYOK tests PR #11454 moved macOS BYOK activation to enrollment-verified fingerprints (isByokActive and usableBYOKEnvironment gate on persistEnrolledFingerprints), and its own test lanes shipped red: the tests store raw keys but never enroll them, so every key reads as inactive. Their teardowns already clear enrollment — the setups now enroll what they store, matching the production activation path. All 8 previously-failing cases (BYOKPaywallTests + the two AgentRuntimeProcessTests BYOK-environment cases) pass locally. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(deploy): enable the daily memory sweep on development The sweep's five deployment inputs were pinned off in every environment, so cohort enrolment alone could never start it -- turning it on for a dogfood account required a second PR. Development now carries the live values: - ENABLED/MODEL_ENABLED on, so the job stops exiting at its first authority gate and the model authority can budget a route. - MODEL_NAME pinned to gpt-5.6-luna, which is the declaration interlock the runner checks against get_model('memories') before any provider call. - MAX_MODEL_COST_USD 0.80, the worst-case pre-call ceiling for a maximal day including phase B's clamped draft/reason/lookup overhead. - COHORT_ENABLED on with COHORT_FLAG daily-memory-sweep-v1, so enrolment is a per-uid PostHog boolean and an unnamed cohort stays a closed rollout. Production is deliberately untouched and stays fully pinned off. The job still cannot form a memory for anyone until that flag exists and resolves true for a uid, which remains a control-plane action rather than a deployment one. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(firestore): terminate the daily-sweep occupant indexes with __name__ The six daily-sweep occupant lookups were the only declarations in the manifest without a trailing __name__ field -- 63 of 69 entries carry one, and main had none missing it. Firestore appends the terminator itself and reports the index back that way, so these six could never match the live inventory. The failure mode is not a missing index; the indexes build fine. It is that reconciliation never converges: every run reports the same six as missing, tries to create them, and fails on ALREADY_EXISTS. That takes down the Firestore schema workflow on both environments permanently, and with it the development backend deploy's readiness gate -- the same class of outage the workflow's own header records from the hourly_usage index in PR #11979. The derived specs previously appended their extra predicates to the base spec's index_fields, which would have placed them after the terminator, so the shared prefixes are now named explicitly and each spec ends with __name__. Verified against real Firestore: reconciliation reports zero missing indexes in both based-hardware and based-hardware-dev. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix: close final JIT rollout and CI gaps Fence direct JIT tools and frame pixels, keep Windows account wipes safe after optional schema failures, and repair inherited CI regressions. Failure-Class: none --------- Co-authored-by: David Zhang <9387252+Git-on-my-level@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> | 4 天前 |
以下内容由 AI 翻译,如有问题请 点此提交 issue 反馈
omi
比你的原生大脑更可靠的第二大脑
Omi 能够捕捉你的屏幕和对话内容,进行实时转录,生成摘要和行动事项,并为你提供一个能记住所有所见所闻的 AI 聊天功能。适用于桌面端、手机和可穿戴设备。完全开源。
已获得 300,000+ 专业人士的信赖。
快速开始
macOS
git clone https://github.com/BasedHardware/omi.git && cd omi/desktop/macos && ./run.sh --yolo
构建 macOS 应用程序,连接云后端,并启动。无需环境文件,无需凭据,无需本地后端。
Windows
git clone https://github.com/BasedHardware/omi.git
cd omi\desktop\windows
npm install
copy .env.example .env
npm run dev
使用 .env.example 中的公共配置从源代码启动 Windows 桌面应用。
要求: Node.js
对于开发工作树,请先运行一次基准本地设置。此操作会安装 Git 钩子,并同步选定的预推送检查所使用的固定后端 Python 环境;移动和桌面运行时环境仍为可选。
make setup
完整安装
如需使用完整后端堆栈进行本地开发:
- 安装必备组件
xcode-select --install
uv --version
- 克隆并配置
git clone https://github.com/BasedHardware/omi.git
cd omi/desktop/macos
cp ../../backend/.env.example ../../backend/.env
- 构建并运行
./run.sh
有关环境变量和凭据设置,请参见 desktop/macos/README.md。
移动应用
cd app && bash setup.sh ios # or: bash setup.sh android
工作原理
┌─────────────────────────────────────────────────────────┐
│ Your Devices │
│ │
│ ┌──────────┐ ┌──────────────┐ ┌───────────────────┐ │
│ │ Omi │ │ macOS App │ │ Mobile App │ │
│ │ Wearable │ │ (Swift/Python) │ │ (Flutter) │ │
│ └────┬─────┘ └──────┬───────┘ └────────┬──────────┘ │
│ │ BLE │ HTTPS/WS │ │
└───────┼────────────────┼───────────────────┼─────────────┘
│ │ │
▼ ▼ ▼
┌─────────────────────────────────────────────────────────┐
│ Omi Backend (Python) │
│ │
│ ┌─────────┐ ┌──────────┐ ┌─────────┐ ┌──────────┐ │
│ │ Listen │ │ Pusher │ │ VAD │ │ Diarizer │ │
│ │ (REST) │ │ (WS) │ │ (GPU) │ │ (GPU) │ │
│ └─────────┘ └──────────┘ └─────────┘ └──────────┘ │
│ │
│ ┌─────────┐ ┌──────────┐ ┌─────────┐ ┌──────────┐ │
│ │ Deepgram│ │ Firestore│ │ Redis │ │ LLMs │ │
│ │ (STT) │ │ (DB) │ │ (Cache) │ │ (AI) │ │
│ └─────────┘ └──────────┘ └─────────┘ └──────────┘ │
└─────────────────────────────────────────────────────────┘
| 组件 | 路径 | 技术栈 |
|---|---|---|
| macOS 应用 | desktop/macos/ |
Swift、SwiftUI、Python 桌面后端 |
| 移动应用 | app/ |
Flutter(iOS 和 Android) |
| 后端 API | backend/ |
Python、FastAPI、Firebase |
| 固件 | omi/ |
nRF、Zephyr、C |
| Omi Glass | omiGlass/ |
ESP32-S3、C |
| SDK | sdks/ |
设备端(Python/Swift/RN + 多语言协议) |
| AI 角色 | web/personas-open-source/ |
Next.js |
文档
快速入门
- 简介
- 快速入门指南
- macOS 应用开发
- 移动应用设置
- 后端设置
- 贡献指南 — 另请参阅
CONTRIBUTING.md和PRODUCT.md
应用构建
API 与 SDK
- API 参考 — 用于记忆、对话、行动项的 REST 端点
- 设备端多语言协议 SDK — 适用于 TS/Go/Rust/C++/Dart 的共享 BLE UUID/数据包帧
- Python 设备端 SDK — 完整的 BLE + Opus + Deepgram
- Swift 设备端 SDK
- React Native 设备端 SDK
- MCP 服务器 — 模型上下文协议集成
架构
Omi 硬件
开源 AI 可穿戴设备,可与移动应用配对实现 24 小时以上持续采集。
许可证
MIT — 详见 LICENSE


