Repository navigation
fix(pendant): free pendant storage only on scoped, content-checked phone proof; recover bad capture dates; storage inventory in Diagnostics - #25405
Conversation
Apply the SD plausibility window to ring, LittleFS and Dart flash imports, preserve run tokens through filename collisions, and keep device reclaim proof independent of clock estimates. Existing retained files remain unchanged for server recovery. Failure-Class: FC-sync-capture-time-zero-tolerance Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Keep the OFF fallback anchored when its first record arrives, matching the previous implementation, and include the mobile release note and shared-policy purpose header. Failure-Class: FC-sync-capture-time-zero-tolerance Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Exercise occupied legacy and corrected nonce names together, retaining existing bytes while checking the backend-adjacent clock-run suffix on new imports. Failure-Class: FC-sync-capture-time-zero-tolerance Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Failure-Class: FC-batch-route-omits-live-custody-proof Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Add a content-free ring_custody section to the existing diagnostic bundle. Read the connected pendant clock without syncing it, expose ledger gaps, and retain bounded protocol events and eight-byte timestamp/framing prefixes. The only custody-manager change is an immutable metadata getter. Observations never supply time estimates, proof validation, dedup or ADVANCE authority. Failure-Class: FC-sync-capture-time-zero-tolerance Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Export read-only counts, clock classes, duration/byte sums and file-reference coverage for active/retired/foreign rows, raw indexes, journals and legacy preferences. Stat recordings and detect unreferenced files or missing refs without invoking any repairing loader, writer, migration or recovery path. Decode and aggregate large inventories off the UI isolate; keep all filenames, account IDs and content internal. Explicitly report unavailable birth times. Failure-Class: FC-sync-capture-time-zero-tolerance Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Do not report a complete orphan census when malformed rows or unresolved file references could conceal ownership. Failure-Class: recording-store-inventory-evidence Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Failure-Class: FC-sync-capture-time-zero-tolerance Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Use a separate immutable mark-state getter with constant work per device, retaining full ledger aggregation only for export. Failure-Class: recording-diagnostics-hot-path Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Failure-Class: recording-diagnostics-contract Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Failure-Class: FC-ring-download-proof-outlives-connection Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Failure-Class: FC-ring-download-proof-outlives-connection Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Failure-Class: FC-phone-durable-pendant-proof Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Failure-Class: FC-phone-durable-pendant-proof Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Exercise an unavailable recording directory in widget fake async. Keep real-file inventory, worker-isolate and privacy checks in the inventory unit suite. Failure-Class: recording-diagnostics-fixture-boundary Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Preserve exact bytes, multiplicity and order independence with sorted lossless frame encodings. Keep the existing timeout and all capture/recovery assertions. Failure-Class: hermetic-replay-comparison-cost Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Failure-Class: FC-phone-durable-pendant-proof Persist explicit indexed markers for empty records, bind every live/batch/download receipt to owner, device and the indexed file SHA-256, reject corrupted and legacy unscoped authority, and stop stalled persistence admission while fencing pending writes. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Failure-Class: FC-phone-durable-pendant-proof Keep the persistence watchdog independently injectable so radio-silence fixtures exercise their own timer contract. Existing no-advance and new stalled-index tests pass together. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Failure-Class: FC-phone-durable-pendant-proof Merge lane/q12-bad-date at 54c78d9 into the separate combined lane. Preserve read ownership, scoped content proofs, exact decoder and proof gaps alongside timestamp plausibility, clock-run boundaries and both read-only diagnostics getters. Use scoped nonempty claims in the diagnostics fixture. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Failure-Class: FC-phone-durable-pendant-proof Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
|
@kodjima33 UI changes involving Git-on-my-level require your approval. Review the current diff, then comment |
Capture-time failures downgrade metadata to unknown without interrupting exact byte/index custody. Scope duplicate validation to incoming record intervals, reuse a revocable per-read index snapshot, and hash fresh bytes for every suppression or ADVANCE decision. Cover unusable clocks, excessive duration, mixed record times, OFF parity, and 10000-row work counts with real indexes. Failure-Class: FC-phone-durable-pendant-proof Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Failure-Class: FC-phone-durable-pendant-proof Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
An unread-duration estimate of zero cannot establish a calendar start. Keep its decoded audio indexed under the existing unknown-time clock run, without changing the clock-switch-OFF arithmetic or exact ring reclaim coordinates. Failure-Class: FC-phone-durable-pendant-proof Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
|
@kodjima33 UI changes involving Git-on-my-level require your approval. Review the current diff, then comment |
Keep the fork regression because it exercises legacy ring_ranges deserialization with a previous-owner index row, distinct from the live_ranges ownerless checkpoint test. Failure-Class: FC-phone-durable-pendant-proof Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Merge the current main normally after retaining the independently useful legacy downloaded-receipt test. Failure-Class: FC-phone-durable-pendant-proof Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Use main PR 25415 bounded reads, exact live-tail boundaries, lost-ACK INFO settlement and shared recording continuity. Keep only the missing indexed range replay, read ownership, persistence watchdog, scoped content proofs, empty markers, batch proof and metadata-only clock repair. Revalidate current bytes on every duplicate skip instead of caching positive proof results. Failure-Class: FC-phone-durable-pendant-proof Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
|
@kodjima33 UI changes involving Git-on-my-level require your approval. Review the current diff, then comment |
|
/approve-ui 4958743 |
Drain pendant safety copies only after exact phone custody is durable
Failure-Class: new
Main PR #25415 already delivered bounded 2,700-record reads, credit before the next READ, live-tail avoidance, shared clock continuity across windows, lost-ADVANCE acknowledgement settlement through INFO, and batched index validation with spent-proof retirement. Its firmware status-poll/buffering changes are also already on main. This PR uses that windowed reader as its base; it adds the missing phone-custody safeguards, interrupted-tail recovery, batch-route proof, bad-date import guard and read-only Diagnostics inventory. Base: origin/main
9c93fa0b2d85fb1232f31fe3f5b88a19a4c406e7; combined head:4958743c0142ed8e86d510bcceb9d5de13ec07c0. Both merges were normal, explicitly reconciled in the two services and custody contract. There is no firmware or executable server diff against this main.Pinned main still accepts unscoped foreign-owner references, corrupted indexed rows, same-length replacement bytes and empty proof lists without files/indexes. A hermetic probe using its exact custody module produced five expected safety failures (including positive-memo revocation) and one passing changed-ring control. The fixes here retain nonempty owner/device-scoped, content-bound exact coordinates and reject those cases. Main's positive whole-window file-result memo is replaced by index-row reuse with fresh overlapping byte checks before every skip and ADVANCE; its index-load and retirement bounds remain tested.
One reader owner covers the entire bounded-window pass through source-connection STOP, queued notifications, indexed persistence and final acknowledgement. Immutable downloaded ranges survive reconnect and restart; exact indexed receipts replay before READ, including an interrupted partial tail, without creating a second recording file. ACKed proof candidates are retired from subsequent ADVANCE work; only freshly revalidated released live refs remain eligible for an in-flight duplicate skip. Download receipt journals remain until fresh INFO confirms the read pointer. Progressing recovery-ON windows have no fixed 5/30-minute completion cap; silence and a separate 45-second persistence-progress deadline stop stalls. Firmware without app-owned reclaim keeps main's single unbounded READ and anonymous completion ACK. The app follows main's window/credit pacing; no additional live-dependent per-chunk sleep is added. Historical unmapped live copies still cannot be reclaimed by inference.
Batch capture preserves the original live session/ring identity and contiguous ordinals only for packets it accepts. Its fsynced checkpoint journal survives restart; publication waits for the exact file prefix and persisted WAL index. Declined packets take the ordinary capture path once. Muting, packet gaps/reordering, new epochs, old firmware and disk failures never widen proof.
R16 corrections require nonempty owner/device-scoped, content-bound references for replay, ADVANCE and duplicate suppression. Ownerless/legacy/hashless proofs, foreign accounts, corrupted WAL rows, missing indexes and changed bytes fail closed. SHA-256 uses the existing upload content-digest scheme. Empty packed records have a canonical fsynced, indexed zero-duration marker before reclaim; an empty reference list cannot authorize a range. The persistence deadline remains active after DATA/DONE and only completed indexed progress renews persistence/coordinator progress. A truly stuck OS write retains ownership until it settles or the process restarts. Previously duplicated audio files are preserved; different filenames are not assumed to receive generic server deduplication.
R16b correction: valid decoded ring audio is persisted even when the phone clock or unread-duration estimate is unusable (including a zero-duration estimate). Estimate construction and the flush plausibility check now downgrade only metadata to explicit unknown time (
timerStart = 0plus the existing clock-run token). They cannot reject a file/index write. The original bytes, owner/device scope, digest and exact ring coordinates still authorize reclaim. Unknown time is not a claim about a calendar capture date or successful server processing. Clock-switch OFF retains the old estimate arithmetic and elapsed offsets.R16b bounded validation: each owned READ window takes one persisted-index snapshot and refreshes it after its own indexed write. DATA checks only proof ranges overlapping its complete record interval; it does not parse the full index or hash unrelated proof files. Same-operation references are deduplicated; positive file hashes are never cached between notifications or ADVANCE decisions. Every production index writer, including the worker, recovery and clear paths, revokes prior snapshots before mutation. A revoked snapshot cannot suppress or acknowledge audio; it does not erase the existing receipt. Independent account, epoch and content fences stay in force. Tests use 10,002 index rows and a 10,001-row fake-pendant READ to count index loads/hashes, verify fresh replacement-byte rejection, and ensure only the gap creates a file.
Q12-AC's guard admits device dates from 2024-01-01 through phone now +24h inclusive. New ring, LittleFS and Dart Limitless imports outside that window receive an estimated time and explicit clock-run token when the phone is a plausible reference. Raw clock resets remain separate runs. Estimates affect import grouping/naming but never substitute for device/ring/session/sequence/ordinal proof keys or indexed byte custody. Existing WALs are not renamed or migrated. Native Limitless writers and the pendant's original clock-error generator remain outside this fix.
The existing Diagnostics JSON gains bounded ring state, RTC observations, protocol history and a local recording inventory: active/retired/foreign memory buckets, raw indexes/backups/quarantines/temporary files, batch journals, ownership receipt counts, loader outcomes, file totals, missing references and uncertain orphans. Large aggregation runs off the UI isolate. It invokes no loader, repair, migration, custody validation or ADVANCE and reads no audio. The export marks unavailable/concurrent sources incomplete and does not export WAL names, paths, owner values or audio bodies. Existing outer device diagnostics identifiers remain; bounded ring coordinates and eight-byte record prefixes are diagnostic metadata.
Safety and failure classification
INV-CAP-1:
product/invariants/pendant-audio-retention.md; custody contracts:app/lib/services/wals/CUSTODY.mdandapp/lib/services/wals/PENDANT_RING_CUSTODY.md. File fsync AND persisted index precede exact-range validation and ADVANCE. Retry/account fences remain. Invalid or partial proof retains the pendant copy for re-download. Timestamp estimates and clock-run tokens never authorize reclaim.This range adds exactly one registry definition, FC-phone-durable-pendant-proof. Its batch, interrupted-download and R16 tests are the prevention artifacts. AC's importer work is also an instance of the existing FC-sync-capture-time-zero-tolerance; that definition is unchanged. The installed protocol permits only one Failure-Class declaration, so the single
newdeclaration covers the added definition and this paragraph records the existing class. Both classes remain represented in the individual commit trailers.Validation
Main's window/cost suite passes 26 tests, including four new window-boundary metadata cases. AA reader/receipt suites pass 62 with two skips; the broader custody/live/batch/coordinator/diagnostics suites pass 154. Capture-clock-OFF passes 88 with two skips; all three switches OFF passes 28 with 13 intentional skips. Changed-service/window-test analysis is clean. The foreign legacy downloaded-receipt test from fork commit
ce0364da11afbc98b664c86a1366a735a19fef68is retained: it tests downloadedring_ranges, distinct from the ownerlesslive_rangescheckpoint case, and its complete file passed formatting and execution.The final committed head is qualified with the full app suite, all journeys, standalone preflight and the installed pre-push hook. Terminal results, exact head/body hashes, the reconciliation table and pinned-main red-probe evidence are recorded in
q12-aa-ring-proof.mdandevidence/q12-aa/main-reconciliation/. Commands:cd app && bash test.sh --concurrency=4;make mobile-verify ARGS="fast --all";make preflight;OMI_PR_BODY_FILE=<this body> BACKEND_UNIT_FILE_BUDGET_SECONDS=900 "$(git rev-parse --git-path hooks/pre-push)" origin "$(git remote get-url origin)" </dev/null, through omi-heavy. These are local hermetic checks, not CI or installed-device acceptance. Earlier green heads and failed integration/control attempts are retained as historical evidence and do not certify this head.UI-Evidence: none -- The diff against merged origin/main changes no widget, layout or user-facing string; device_diagnostics.dart only adds a section to the existing shared JSON. The evidence gate scans all app/lib Dart paths and explicitly accepts this truthful no-visual-change declaration; no screenshot or evidence manifest is needed.
Device acceptance
Install the combined artifact while preserving app data; do not uninstall, clear storage or reset the ring. Use firmware 3.0.24, all three repair switches ON, adequate phone disk, charging and a foreground connected app. Keep pendant recording live. At baseline, +2 minutes and +10 minutes (extend for UI rounding), record Device Storage used/total/free/percent and these Offline Sync numbers: Waiting on your Omi duration and MB; Waiting on this phone duration; Transcribing on Omi duration; Downloading from your Omi done/total and fraction. Export Settings → device → Diagnostics → Share at the same points and record phone UTC, ring identity, read_seq/write_seq, dropped count, capacity/used and persistence grant.
PASS requires Device Storage used to FALL while connected AND recording; within the same ring, read_seq must gain faster than write_seq, dropped count must not rise, saved audio must play, and new live capture must continue. Faster draining only while recording is paused does not pass. Reconnect/cancel during persistence and restart after index-before-receipt must replay the known prefix before READ without making a second audio file. Missing index, changed/corrupted file, foreign owner, wrong ring, ownerless legacy proof and unknown prefix must retain audio. Verify empty markers are indexed control metadata, never uploaded as audio. Physical RF/background/power-loss/disk-pressure behavior, digest cost, owner export, live Home display of estimated dates and sustained drain remain unverified here. Firmware 3.0.24 broad rollout remains gated on the live-recording storage decrease.
Rollout and rollback
RELEASE ORDER: A build containing the bad-date guard MUST NOT go to the App Store before server recovery PR #25401 (#25401) is serving with its recovery switch ON and its readers qualified. Until then an impossible-date import carries an estimated time that the server treats as an ordinary date. Verify the serving revision and switch before releasing this app; local tests do not establish that prerequisite. Qualify how Home presents untrusted display time separately.
All three repairs are ON by default. Rebuild with
--dart-define=OMI_RING_DRAIN_RECOVERY_OFF=trueto restore main's windowed-reader behavior without AA indexed-tail reconstruction, exit-path recovery or downloaded-span suppression;--dart-define=OMI_BATCH_RING_PROOF_OFF=trueto restore the prior batch proof behavior;--dart-define=OMI_DEVICE_CAPTURE_CLOCK_REPAIR_OFF=trueto restore previous new-import timestamp predicates and naming. Use all three for a full behavior rollback. Conservative proof validation remains enforced. Already-reclaimed pendant copies cannot be restored by a flag; their indexed phone files must be preserved. Existing estimated runs and old files are not rewritten. Keep compatible server readers for estimates already admitted.No remote lease was added: the existing flags path can return an unbounded last-known-good ON value and exposes no server-validation age. A fresh HTTP read cannot establish a fresh grant. A fail-closed remote switch needs a bounded server grant/cache-freshness contract and client lease checks, beyond a configuration-key change; this follows the lead's exception. The three compile-time switches remain the available rollback controls.
File growth
Counts below are actual origin/main → combined-head source counts. Declarations for files below the 1,500-line threshold also document the requested integration boundaries; the ratchet may report those as unnecessary.
Line-Count-Exception: app/lib/services/capture/capture_controller.dart | 4941 -> 4944 | Preserve original packet coordinates at the existing batch routing boundary without introducing another capture owner.
Line-Count-Exception: app/lib/services/wals/local_wal_sync.dart | 2789 -> 2864 | Publish owner-scoped indexed content proofs and expose primitive inventory observations at the existing WAL owner.
Line-Count-Exception: app/lib/services/wals/pendant_ring_custody.dart | 1102 -> 1743 | Keep exact receipt replay, account/content validation and contiguous ADVANCE decisions in the single custody authority; retain immutable diagnostics getters.
Line-Count-Exception: app/lib/services/wals/ring_storage_sync.dart | 1230 -> 1551 | Keep streaming read ownership, persistence deadlines, empty-record markers, exit acknowledgement and timestamp normalization beside the existing parser.
Line-Count-Exception: app/lib/services/devices/connectors/omi_connection.dart | 1498 -> 1580 | Observe bounded read-only protocol events beside connector operations without altering protocol authority.
Line-Count-Exception: app/lib/pages/settings/device_diagnostics.dart | 1091 -> 1094 | Add one JSON export section to the existing diagnostic builder without changing presentation.
Line-Count-Exception: app/lib/services/wals/wal.dart | 1204 -> 1303 | Persist exact source coordinates and the existing SHA-256 content identity with the WAL serialization that owns indexed custody.
🤖 Generated with Claude Code