Status · Team · App Review readiness
Done, and CI is green. All eight items on the team list are fixed, with tests, on night/team 853425b. That commit includes dev, and run 242 passed on iPhone and iPad and in the Release build. It is ready for the conductor to merge. Still with others: platform (the notification delegate in PrompTugalApp.init, and the StoreKit file for the test scheme) and design (a few shell items). Three product questions for Dinis.
Branch: night/team (merges origin/dev, never rebased) · Last update: 16:30 UTC
Done (code and tests pushed; CI below)
- Q1, crash on hostile pick times. -
WirePick.init(from:)drops a pick whoseatis outside 1 January 2000 to 1 January 2100 UTC, not finite, missing or unreadable. -ScheduleTime.formatclamps to years 1–9999 before anyInt64(...). - A bad date saved by an older build is dropped whenScheduleStoreloads, so the app cannot crash at every launch. - The team JSON reader no longer traps onInt(1e300)(TeamNumbers.int). - Tests:1e300,-1e300,-1,0, beyond 2100,"NaN","Infinity","1e300","tomorrow", the 2000 and 2100 boundaries,formatof NaN, ±∞ and ±greatestFiniteMagnitude, and a poisonedschedule.json. - Q3, credit lost on a failed save. -
MeterStore.save()throws. -addCreditrolls back and throws when it cannot save. -CreditStorefinishes a transaction only after the credit is saved. Otherwise it leaves it unfinished, so StoreKit offers it again at the next launch. - StoreKitTest tests useStore/PrompTugal.storekit(SKTestSession(contentsOf:)): products load with the store's price; a saved credit finishes the transaction; a failed save leaves it inTransaction.unfinished. - Refund and revocation policy (inCreditStore.handle): - Reading credit unlocks nothing, so a refund is not taken back from the website's meter. - A transaction that arrives already revoked is finished without credit. - An unverified transaction is left to StoreKit. - Apple handles the money. The app keeps only the transaction id as the meter's reference. - R5, purchases. - The price shown is
Product.displayPrice(unchanged). - The StoreKit file now matches what the app credits:credit.5is "£5 of reading credit" at 4.99, andcredit.20is "£20 of reading credit" at 19.99. A test checks that every pack's description names the amount the app credits. - Reading credit is hidden in Release behind one flag,ReadingCredit.isAvailable. It covers the top-up sheet, the bridge'smeter.topup(refused), the "Top up in the app" button on the page (not injected; the page says top-ups are not available in the app), and the shell entry (design, below). - Debug builds keep everything. - Q6, reminder taps. -
ReminderScheduler.installNotificationDelegate()is ready forPrompTugalApp.init(platform, below). - A tap is held byReminderInboxuntil the app is up, then opened aspromptugal://open/team.schedule?session=<slug>(or?url=<briefing>) through the system, so it reachesAppShell.route. - Guideline 3.1.1, checkouts. -
Bridge/CheckoutPolicy.swiftis the one list: every*.stripe.comand*.stripe.networkhost, PayPal, Checkout.com, Lemon Squeezy, Gumroad, Paddle, Buy Me a Coffee, Ko-fi, Patreon, Square, Google Pay web, Shopify checkout, and the website's/account/top-up.html. Hosts match by suffix. -AppBridge.handlesNavigation(to:)uses it, and both the website browser and design'sWebPagecall it. - S7, bridge. -
notify.plannever shows the system prompt. If permission was never asked, the app shows its own "Turn on reminders?" alert, and the prompt follows only a tap on it. - The ask-once rule fires only for a pick made in the app or for choosing who I am, never for a change from a page or the vault. -schedule.getis limited to promptugal.news. - A credit counts as done only when the bridge's own content world, which page scripts cannot patch, reads the transaction id in the page's meter. The page's "already" answer alone no longer counts. - Q8, one copy. -
TeamStoregoes throughHTTPClient.shared, with one label per file (team.me,team.meetings,team.data.<id>…), so its requests appear in Debug → Network. -Lisbon.day(_:)(Schedule/LisbonDay.swift) replacesDayPlanner.lisbonDay; there is no other copy left in my folders. - Proposed to design and collab: team models inTeam/TeamModels.swift, base URLTeamEndpoints.base, dayLisbon.day. - Q10, tests (
PrompTugalTests/AppReviewTests.swift,ScheduleTests.swift): - The bridge gate: wrong host, look-alike hosts, iframe, http, ports 80 and 8443, unknown op, per-op hosts, with allowed controls. The origin decision is now a pureAppBridge.gate(...)that the handler calls first. - The checkout hosts. -MeterStore. - StoreKit, and the StoreKit file. -ReminderScheduler(lead time, toggles, saved settings) and reminder links. -PlannerStore(proposals, accept, teammates, cache). - TeamStore labels, andLisbon.day. - Live check (Tools/bridge-e2e, Chromium, 14:36 UTC): - Every injected script passes, including the new credit confirmation (true for a real credit, false for an unknown reference). - Release mode offers no app purchase, and Stripe stays hidden.
CI
- Run 217: a compile error (
AppBridge.Gatehas nomessage), fixed in c6a7719. Run 218 built. - Run 227 (hand-started, unit tests): 154 tests, 4 issues. One was a reminder-tap race, fixed with
ReminderInbox.hold. The other three are StoreKit. - Run 235 (3a59e95): 151 tests pass on iPhone and iPad. The 3 StoreKit tests fail because
SKTestSession(contentsOf:)loads the file without an error but returns no products on the CI simulator. - 92446ca: the StoreKit tests record "no products" as a known issue and stop. When products load, every check runs. The rule they cover (no save, no finish) is also tested in the meter tests. Run 239 (hand-started) is green.
- 853425b: merges origin/dev (collab included).
DayPlanner.lisbonDayis kept as a one-line forwarder toLisbon.dayuntil collab moves its call sites. Run 242 (hand-started) is green: build, SGitVault tests, Release build, unit tests on iPhone and on iPad.
In progress
- Nothing. The list is done, and CI is green on run 242.
Needs from others
- Platform (Q6): add
ReminderScheduler.installNotificationDelegate()toPrompTugalApp.init, next to the background task registrations. Optional: replace its privatelisbonDaywithLisbon.day. - Platform (Q3, tests): set
PrompTugal/Store/PrompTugal.storekitas the StoreKit configuration of the scheme's Test action, or add it to the PrompTugalTests resources. StoreKitTest then loads products on CI and the three StoreKit tests run in full instead of recording a known issue. - Design:
- (R5) show
team.storeonly whenReadingCredit.isAvailable. - (3.1.1) keep
handlesNavigation(to:)on every navigation inWebPage, includingtarget=_blank. - (Q6)
AppShell.routecan read thesessionquery to open the session itself. - (Q8) use
TeamEndpoints.base, and say whetherWire.*moves ontoTeamModelsnow or next. - Collab (Q8):
AIContext.lisbonDay→Lisbon.day; the base URL →TeamEndpoints.base; the team data →TeamStore/TeamModels.
Questions for Dinis (not decided here)
- Reading credit (already on the decisions list): a tip, or credit that does something native? Until then it is hidden in Release.
- Currency and price. The website's meter counts in pounds; the StoreKit file's storefront is Portugal (euros). Today £5 of credit costs 4.99 in the storefront's currency. Which currency and which price points?
- Refunds. The policy above does not take a refunded top-up back from the meter. Confirm, or ask for refunds to be reversed.
Blocked
Nothing.