Status · Collaboration and AI (App Review readiness)
Done and CI green: all seven items, with tests, on dev since 7d135e0. Follow-up done: Lisbon.day(_:) in my three call sites; run 252 (cc3f4ae) green on Release build, app build, SGitVault tests and iPhone and iPad unit tests. Ready to merge.
Branch: night/collab (merged from origin/dev 2bc718a, no rebase) · Last update: 17:08 UTC
Done (pushed, with tests)
- R2/S2 consent before Ask sends anything (
AI/ChatStore.swift,AI/AskView.swift,AI/AIContext.swift,AI/AITools.swift) - A sheet before the first question names OpenRouter (openrouter.ai) and the model's provider (from the model id, e.g. Anthropic), lists each kind of context with its own switch and what it sends, and offers Allow / Don't allow. - The choice is stored (ai.consent.v1). Ask settings show it and offer "Withdraw permission" or "Ask me again". "Don't allow" is not asked again on every question; Ask shows that it is off. - No request is built without consent: checked insend,askand again inrun. - Context defaults to the public agenda only (new keyai.context.v2, so earlier wider choices are not carried over). - Teammates' plans (where_is_everyone) and Current page are separate, explicit switches, off by default. - Prepared prompts cannot widen what is shared; tools are offered and run only for switched-on data. - Tests: no request without consent (an injectedHTTPLogstays empty), decline is stored and not re-asked, withdraw goes back to asking, default context is[.agenda], prompts cannot widen, tools gated, provider names. - R4 report and block on Messages (
Lanes/LaneReport.swift,Lanes/LanesStore.swift,Lanes/LanesView.swift,Lanes/TeamNotes.swift) - Block a lane, or the sender of an inbox message or a teammate's note: hidden everywhere on this device, persisted, and undone in a "Blocked" section. - Report… opens a prefilled mail (subject, sender, date, the text). The address is one constant,LaneReport.contactAddress, empty until Dinis gives it; the mail then opens with no recipient. - Context menus, swipe actions and VoiceOver actions ("Report", "Block sender"). - Tests: block persists across stores and unblocks; report URL is prefilled and header-safe; works before the address is set. - Q4 crypto off the main actor: RSA-4096 generation (
makeMyLane) and inbox decryption (LanesStore.decryptAll) run inTask.detached; the website inbox key is imported inside that task. Test: messages open throughdecryptAll, a bad one gets a readable error. - S5 key only from my own vault (
Coordination/CollabHooks.swift,Coordination/CollabVaultGlue.swift,AI/AIKeyStore.swift) - The vault seam hasownVaultId: the account's reader vault. An imported key (a teammate's) is never "mine". -loadFromVaultreads only that vault; saving the key, sharing my plan and posting team notes write only to it, and fail with a plain message otherwise. - Tests with a fake vault: a teammate's vault is never read for the key; my own is. - S7 - Links in Ask answers: tapping one shows the full URL and asks first; only
httpsandmailtocan be opened, other schemes (includingpromptugal://) only copied. Test. - Copy from Ask: local only (no Handoff) and expires after two minutes. Test. - Lane endpoints: onlyhttps://dev.send.sgraph.ai(no port, no user); checked when parsing, for the website inbox record, and on every request. Tests (other host, http, port, credentials, a changed address at send time). - Append tokens: lane addresses moved from UserDefaults to the Keychain; the old copy is migrated once and deleted. Test checks no token remains in UserDefaults. - Smaller fixes -
isSendingis set before the Task is created, so a double tap sends once. - Conversation capped at 200 turns; at most 30 sent back with a question. Test (messages builder). - Messages on iPad: two columns only when the window is at least 700 pt wide; one list in narrower Split View. The fixed 400 pt is gone. - One Lisbon-day helper: my copy is deleted and I call team'sDayPlanner.lisbonDay. - One set of team models: Ask's team context and "Where is everyone"'s people list now readTeamStore'sTeamPersonandCommandCentre(no separate fetch or parse). Tests decode fixtures through those models. - Debug literals inAskViewandLanesViewuseDebugMode.key/DebugMode.defaultOn. - Readable errors (Q7):
CollabErrorText.shortfor every error shown inAI/,Lanes/andCoordination/: network errors in plain words, noError Domain=…, no object paths. Test.
CI
- Run 252 (workflow_dispatch, cc3f4ae, after team landed and the switch to
Lisbon.day(_:)): green. Release build (device, unsigned), app build and SGitVault tests, iPhone and iPad unit tests. - Run 233 (workflow_dispatch, 7ca0a00): green. App build and SGitVault tests, App unit tests on the iPhone and the iPad simulator (all suites, including AIConsentTests, AIKeyVaultOwnershipTests, AILinkTests, LanesReviewTests).
- Earlier build-only runs: 203, 209, 214 green. Run 226 failed to compile one test helper (a raw-string fixture at AITests.swift:183); fixed in 7ca0a00.
In progress
- Nothing.
Lisbon.day(_:)switch done (AIContext, AITools, CoordinationStore).
Blocked
Nothing.
Needs from others
- Team: done; I use
Lisbon.day(_:).TeamStorestill fetches withURLSession.shared(Q8); my team context now goes throughTeamStore, so routing it throughHTTPClientwill put those requests in Debug → Network too. - Vault: my
ownVaultIdtreats the reader vault (byreaderVaultIdor role "reader") as mine and "imported" as never mine. If your S5 fix adds an explicit "mine" marker for a pasted own key, tell me and I will use it. - Design:
DebugMode.defaultOnfalse in Release is yours; my views follow it.
For Dinis
- Contact address for reports: set
LaneReport.contactAddress(one line) once decided (pack decision 3).