Eight blocking findingsfindings/REGISTER.md · raw .md
Eight blocking findings
1. BLOCKER
| ID | Title | Final severity | Original severity | Verdict | File:line (at 03a176e) |
Evidence path | Refuter note |
|---|---|---|---|---|---|---|---|
| S1-F1 | A backward step of the wall clock silences every running timer for the length of the step | BLOCKER | BLOCKER | CONFIRMED | lib/engine/engine.dart:312; deadlines set at :177, :182; consumer lib/ui/home.dart:248 |
findings/S1_engine.md · proof/01_findings/S1/ · proof/01_findings/S1_refute/ |
Reproduced on an independently built clean copy; heartbeat proven monotonic (so the app is awake and silent); backstop proven to run on the same RTC_WAKEUP wall clock, so it does not rescue this. Three corrections: the Evidence block is a stitched composite, not verbatim — replace it with s1_facts_test.dart:92-121 as written; the silence is bounded by the size of the step, not permanent; the proposed fix is defective as written (probe R2b) and must be redesigned before implementation. |
| S2-F2 | The zone→sound migration is NOT idempotent: a second run rewrites every dish's ringtone to Bell |
BLOCKER | BLOCKER | CONFIRMED (strengthened) | lib/engine/store.dart:255-285; false claim at :249-252; mechanism lib/engine/models.dart:56-63 |
findings/S2_persistence.md · proof/01_findings/S2/ · proof/01_findings/S2_refute/ |
Reproduced twice from scratch, once with no write failure at all — the trigger needs no wrong-typed value. One wording correction: _guard (store.dart:174-180) does observe and report the write result; what it does not do is raise it as critical, retry, or let a caller await it. Delete "never verifies" before this reaches the report. |
| S3-F1 + S9-F07 (+ prior A1-1, iOS half) | The OS alarm backstop is dead on iOS: the notification plugin is initialised Android-only and no iOS sound resource is bundled, so the app boots into a permanent red banner and iOS has nothing to play | BLOCKER | BLOCKER (S3) / HIGH (S9) | CONFIRMED — S9-F07 raised HIGH→BLOCKER | lib/alarm_backstop.dart:72-76 (InitializationSettings has no DarwinInitializationSettings); _ready gate :79-96; ios/Runner.xcodeproj/project.pbxproj PBXResourcesBuildPhase block 97C146EC1CF9000F007C117D (no sound resource) |
findings/S3_audio_alarms.md · findings/S9_platform_config.md · agent_reports/S3_refute.md · agent_reports/S9_refute.md |
Found independently by S3 (audio/backstop angle) and S9 (platform-config angle). S3's refuter verified the defect against the plugin source at flutter_local_notifications_plugin.dart:142-147 and by mutation B4. S9's refuter raised its own F07 to BLOCKER and folded S9-F03's blocking condition into it. Also the still-open half of the 2026-07-19 prior audit's A1-1. |
| S3-F2 + S9-F03 | An iOS build cannot ring at all once it leaves the screen: UIBackgroundModes is absent from the whole Info.plist |
BLOCKER | BLOCKER (both) | CONFIRMED — S9-F03's proposed fix REFUTED | ios/Runner/Info.plist:4-69 — key absent from the top-level <dict> (file is 70 lines, not the 63 S3's manifest records) |
findings/S3_audio_alarms.md · findings/S9_platform_config.md · agent_reports/S3_refute.md · agent_reports/S9_refute.md |
Both refuters enumerated the plist keys themselves and confirmed the absence (grep -c UIBackgroundModes → 0; 18 top-level keys). S9's refuter split the finding: the fact holds, but adding UIBackgroundModes does not fix it — the blocking condition belongs to S9-F07 (the merged row above) and that is where the Phase-4 fix goes. Do not implement S9-F03's fix as written. |
| S3-F3 | setStreamVolume failure is swallowed in Kotlin and never verified in Dart, so the 15 % audible floor is a claim the app cannot back |
BLOCKER | BLOCKER | PARTIALLY REFUTED — BLOCKER stands, mechanism refuted | android/app/src/main/kotlin/dev/sergemio/cadence/MainActivity.kt:57-59 |
findings/S3_audio_alarms.md · agent_reports/S3_refute.md §Part 1 · proof/01_findings/S3_refute/ |
The severity survives; the justification does not. The refuter went to AOSP AudioService.java:4495-4504, :3745-3765, :4613-4626, :6724-6752 and proved the cited SecurityException cannot fire at this call site — the app passes flags = 0, and the throw is guarded by wouldToggleZenMode(getNewRingerMode(...)) which needs FLAG_ALLOW_RINGER_MODES. Consequence: fix (1) (reply result.error(...)) is inert; promote fix (2) to the whole remedy. See S3R-F2. |
| S9-F01 | The release build type signs with the debug keystore; both APK and AAB carry CN=Android Debug, which Google Play does not accept |
BLOCKER | BLOCKER | CONFIRMED | android/app/build.gradle.kts:30-36 |
findings/S9_platform_config.md · proof/01_findings/S9_refute/ |
Reproduced on the refuter's own build of both artefacts. Policy source: https://developer.android.com/studio/publish/app-signing. |
| S9-F02 + R-F1 (S11's refuter) | The iOS App Store icon set is the byte-identical Flutter placeholder logo; flutter_launcher_icons was configured to skip iOS |
BLOCKER | BLOCKER (S9) / — (new, S11R) | CONFIRMED and strengthened | pubspec.yaml:35 (ios: false); ios/Runner/Assets.xcassets/AppIcon.appiconset/*.png — all 15, not only Icon-App-1024x1024@1x.png |
findings/S9_platform_config.md · agent_reports/S9_refute.md §BLOCKER 2 · agent_reports/S11_refute.md §7 R-F1 |
Found twice, independently. S9 found it from the platform-config side and graded BLOCKER; S11's refuter found it from the asset-provenance side after discovering S11 had omitted ios/ from its inventory entirely (R-F2), and graded it BLOCKER without knowledge of S9's row. S9's refuter proved all 15 icons are template, not just the 1024. Root cause is a single line: pubspec.yaml:35. |
| S9-F04 | The iOS project has never been configured for a real signing identity, and the required Xcode/SDK toolchain is not installed | BLOCKER | BLOCKER | CONFIRMED | ios/Runner.xcodeproj/project.pbxproj:349, :469, :526 (no DEVELOPMENT_TEAM) |
findings/S9_platform_config.md · agent_reports/S9_refute.md §BLOCKER 4 |
Confirmed, and the 2026-04-28 Xcode-26 requirement date verified verbatim against https://developer.apple.com/news/upcoming-requirements/. |
BLOCKER count: 8 rows. S9's refuter's summary holds — the platform stream's BLOCKER count is unchanged at 4, but one of them changed identity (F03 → F07), and with it the Phase-4 fix.