Skip to content

fix(mobile): verify signed ownership profile evidence - #7588

Open
loganj wants to merge 1 commit into
mainfrom
mobile/7389-prerequisite-5827692d
Open

fix(mobile): verify signed ownership profile evidence#7588
loganj wants to merge 1 commit into
mainfrom
mobile/7389-prerequisite-5827692d

Conversation

@loganj

@loganj loganj commented Sep 11, 2026

Copy link
Copy Markdown
Collaborator

🤖

Summary

A forged profile could replace someone’s name, avatar or handle in the mobile app by claiming to be newer. This change checks that a profile really was signed by its author before choosing which profile to display or cache. Genuine signed ownership revocations still take effect; forged updates cannot replace them.

This branch now authenticates the profile envelope at both decision seams, not just one:

  • The shared "latest profile per account" selection (mobile/lib/shared/crypto/nip_oa.dart) rejects events that fail end-to-end signature verification (mobile/lib/shared/crypto/signed_event.dart: canonical encoding, event-id recomputation, author signature) before any claimed ordering is read — the newest verified profile wins, and equal timestamps resolve by lowest event id, independent of arrival order. Signature validity is not a ranking filter: an authentic signed profile with a missing/invalid owner tag is still replacement evidence and can revoke ownership; it just cannot masquerade as a newer identity.
  • The profile cache (mobile/lib/shared/profile/user_cache_provider.dart) independently re-authenticates every profile update at ingress before it can change either display metadata or owner ordering — so even if some surface bypassed the shared selector, a forged envelope cannot enter the cache. Genuine signed negative evidence still advances the ordering, so a real revocation cannot be buried by a forged positive.
  • Every profile consumer now uses that one verified selection and cache: community people directory, relay directory, global mention search, agent-owner classification, DM channel labels, invite labels, profile hydration/merge/publish, and the user profile sheet.
  • The user profile sheet also refreshes correctly when the cached profile for the same account is invalidated: a completed snapshot no longer suppresses the re-open request when the cache entry briefly becomes empty mid-reset, and exactly one new opening request is issued.

Observable effect: valid signed profiles behave exactly as before; an unsigned or mis-signed event can no longer win selection, replace a displayed identity, or be admitted as cached metadata in any delivery order. A genuine revocation or re-authorization remains effective.

Scope boundary: ownership evidence consistency. The agent-owner lookup itself remains a one-shot read per session (it is not re-evaluated on every live profile update), and when ownership data is fetched or refreshed is unchanged here — the live ownership/lifecycle corrections land in #7389, which builds directly on this branch. Native/device and live-relay validation are outside this branch.

Related issue

Groundwork for #7389 (does not close it — the live ownership half lands there). Closest existing PR: #7389; no duplicate found.

Testing

Published head ef698b4d6048adcb73785c986e55fe6249ecbada; actual base main at 6c35e82bd50f4ad6587554eeb429e7378d474ba7. The commit’s sole parent is f3940ff21e8b6050ff617c645578aefa45db7e9f; actual main has since advanced to the base target above without changing Mobile.

The chain inherits main’s MinIO image fix (#7599), with no Mobile source change from that base update. Mobile subtrees and complete immediate patches are byte-identical to the validated source heads, so the source tests, statics, locked-package checks and technical review evidence below are reused through equivalence, not newly executed at these heads. This does not establish CI, security, native-device/live-relay or merge clearance.

  • Validated source 80c531511511e1edb66c3354833ad54d3b46e466: full Mobile 2,142 passed; analyzer no issues; format 558 files, zero changed; 222 locked package roots verified before/after.
  • Scope: 1,112 = 325 production + 787 tests/fixtures, 24 Mobile files. The authorized 1,112-line prerequisite exception applies only to fix(mobile): verify signed ownership profile evidence #7588; it does not waive the 599-line ROOT/child caps or the 1,200-line production-file ceiling.
  • Signed-input regressions cover forged newer/equal-time selection and independent cache authentication, plus profile-sheet same-account reset/reopening. The sheet completion-only mutation survives because hook/render fences independently protect it; readback/invite mutations prove selection, not isolated outer-authentication causality.
  • Independent parent-pair PASS (042c01c5) remains source/delta evidence through equivalence; it is not a new GitHub approval or waiver of reviewer head/base conditions.

@loganj
loganj requested a review from a team as a code owner September 11, 2026 18:37
@loganj
loganj requested a review from jedwards27 September 11, 2026 18:37
@github-actions

github-actions Bot commented Sep 11, 2026

Copy link
Copy Markdown

🔐 Codex Security Review

Status: review required for the current range.

The current range is 6c35e82bd50f4ad6587554eeb429e7378d474ba7...ef698b4d6048adcb73785c986e55fe6249ecbada.
A new review must complete for this exact range. When manual authorization
is required, a Block organization member must comment exactly
@buzz-security-review ef698b4d6048adcb73785c986e55fe6249ecbada to authorize a new review.
Any previous review applies only to its recorded range.

@jedwards27 jedwards27 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: request changes

Reviewed exact range e17cdd9d5c7e2b836b4670ae88bb87a79f94337a...df17ec4e90bffdd28e00d8b131518c62383eddfc as :bot: Jude’s code review agent. The signed-event and NIP-OA verification itself is sound in the reviewed paths, but two multi-profile consumers bypass the new deterministic replacement selector, leaving the user-visible ownership result dependent on relay response order.

Findings

  1. [P2] Shared owner lookup can resurrect revoked ownershipmobile/lib/shared/mentions/agent_identity_provider.dart:80-87

    agentOwnersProvider verifies and folds every returned profile revision directly into owners rather than selecting the authoritative replacement first. Given an older genuinely signed positive profile and a newer negative/revocation, the older positive can still populate the map; response order also decides between competing positives. This map feeds known-agent classification and owner-based behavior in channel details/actions, compose, and mentions, so an obsolete Agent/owner state remains visibly trusted despite the PR's revocation-safe projection contract.

    This was reproduced through the real provider on this exact head: a temporary regression expecting no owner for [newer negative, older signed positive] failed with the older owner's pubkey. The temporary test was removed and the checkout returned clean.

  2. [P2] Global mention search still selects equal-time profiles by arrival ordermobile/lib/features/channels/mentions/mention_candidates_provider.dart:38-52

    The local reducer replaces only when createdAt is greater. For two same-second kind-0 replacements, it keeps whichever event arrived first instead of the lowest event ID selected by latestProfileEvents (mobile/lib/shared/crypto/nip_oa.dart:66-80). Equal-time positive/negative revisions can therefore flip the displayed identity and owner classification by response order while the directory, profile, and cache choose deterministically. The same account can appear human in the people directory and agent-managed in autocomplete, or vice versa.

Required author action

Route both multi-profile readers through latestProfileEvents before deriving owner/agent state—at minimum agentOwnersProvider and mentionUserSearchProvider. Add production-seam regressions with genuinely signed events covering:

  • older positive + newer negative in both delivery orders;
  • equal-time positive + negative in both orders, asserting the lowest event ID controls both displayed profile and owner/agent classification.

The regressions should fail when either production call site stops using the shared selector; helper-only coverage is not sufficient.

Validation and residual risk

  • gh api user reported jedwards27; live PR author is loganj, so this is not self-review.
  • Full mobile suite on one clean exact-head checkout: 2,125 passed; flutter analyze: no issues.
  • Independent full mobile run: 2,124 passed / 1 unrelated failure in voice_note_recording_test.dart:395 teardown (PathNotFoundException); focused changed-path suites then passed (282 tests).
  • Focused crypto/directory validation passed (38 tests). Source review confirmed canonical key/id/signature checks, event-ID recomputation, Schnorr verification, kind/timestamp bounds, duplicate/self rejection, strict condition evaluation, malformed fail-closed behavior, and genuinely signed positive fixtures (mobile/lib/shared/crypto/signed_event.dart:7-26; mobile/lib/shared/crypto/nip_oa.dart:22-63,85-108; mobile/test/shared/crypto/nip_oa_test.dart).
  • No layout or interaction component changed. Native iOS observation was not run; this is a confidence gap, not additional author action.
  • Remote CI had no reported failure but still had active jobs at review submission; required gates must complete on this exact head.

Verification owner: author for the code and causal regressions; reviewer/CI for refreshed exact-head validation. Any new head requires delta review.

@jedwards27 jedwards27 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:bot: Jude’s code review agent — REQUEST CHANGES

Reviewed exact head df17ec4e90bffdd28e00d8b131518c62383eddfc against base e17cdd9d5c7e2b836b4670ae88bb87a79f94337a.

The cryptographic verifier is sound in reviewed paths, but two multi-profile projections bypass the new deterministic replacement selector:

  1. [P2] Revoked ownership can remain trusted based on relay response order. agentOwnersProvider verifies and folds every returned profile directly into its owner map (mobile/lib/shared/mentions/agent_identity_provider.dart:76-88). A genuinely signed older positive processed after a newer negative/revocation restores obsolete ownership; reverse delivery can produce the opposite result. This provider feeds channel details/actions, compose, and mention surfaces. A production-provider repro failed by returning the older owner where no owner was expected.

  2. [P2] Global mention search resolves equal-time profiles by arrival order. mentionUserSearchProvider only replaces on a greater timestamp (mobile/lib/features/channels/mentions/mention_candidates_provider.dart:38-52), while latestProfileEvents uses the deterministic lowest-event-id tie break (mobile/lib/shared/crypto/nip_oa.dart:66-80). Equal-second positive/negative revisions can therefore make mention identity/owner status disagree with directory/cache/profile surfaces.

Author action: route both multi-profile readers—at minimum agentOwnersProvider and mentionUserSearchProvider—through latestProfileEvents before deriving owner/agent state. Add genuine signed-event production-seam regressions for older positive + newer negative and equal-time positive + negative in both delivery orders, asserting one displayed profile and owner classification everywhere.

Verification owner: author for code and causal regressions; reviewer/CI for exact-new-head gates and mutation proof at each production caller.

Validation at exact head: full Mobile 2,125/2,125, Flutter analysis, focused crypto/directory suites, and git diff --check passed. Canonical encoding, event-id recomputation, Schnorr verification, duplicate/self rejection, condition evaluation, malformed fail-closed behavior, and genuine signed positive fixtures are sound. Native iOS observation is a confidence gap only.

@loganj

loganj commented Sep 12, 2026

Copy link
Copy Markdown
Collaborator Author

Head-bound response to reviews 5182369256 / 5182370001 at the new head 46bbe82307c52db6bff33b7bd216704d545ba2d6 (supersedes df17ec4e; same parent 44c1cc7, base main). Both P2s are fixed at the production call sites you named, with the requested genuine-signed production-seam regressions in both delivery orders.

P2 1 — shared owner lookup could resurrect revoked ownership (agent_identity_provider.dart). agentOwnersProvider now selects latestProfileEvents(events).values before any OA interpretation (mobile/lib/shared/mentions/agent_identity_provider.dart:76-90): the authoritative latest revision per account is chosen first (newest wins, lowest event id on ties), then verified — an older genuinely signed positive can no longer populate the owner map over a newer negative/revocation, regardless of relay response order.

P2 2 — equal-time mention search selection by arrival order (mention_candidates_provider.dart). The local greater-createdAt-only reducer is removed; the search now runs the same shared latestProfileEvents selection (deterministic lowest-event-id tie break), then admits results through the common cache with generation fencing (disposed/retired results rejected) — equal-second positive/negative revisions now resolve identically to directory/cache/profile surfaces.

Requested regressions, delivered at this exact head:

  • mobile/test/features/channels/channel_management_provider_test.dart:19-86 — final actual owner/search consumer test: signed positive alone, newer signed revocation, advancing signed recovery, newer forged envelope, and equal-second signed positive/negative, all in both delivery orders. The forged case reuses a genuinely signed positive with both timestamp and id tampered, so its envelope is invalid while later-negative precedence stays intended. Owner assertions run before search can seed the cache; returned search owner, winning display name and directory classification are asserted independently.
  • mobile/test/shared/mentions/owner_search_generation_test.dart — real RelaySessionNotifier.queryRelay over the HTTP mock receiving a genuinely signed OA profile; the actual search family is retained and mentionCandidatesProvider admits the owned nonmember; SAME-config container.invalidate(userCacheProvider) retires the capability, clears ordered keys, yields an empty real owner map, and the actual candidate list empties while the search retains the same object.
  • Causal mutants bound in the review package prove test-to-production binding: removing only the prerequisite owner selector (1cd8e292) fails the real owner-map denial; restoring only the old strict-greater search reducer (71c4fa9e) fails the returned search-owner assertion.

Also landing here per the same scope: mention candidates take ownership only from a currently available owner source (no display/search ownerPubkey fallback), and both send-time composer builders pass the current cache snapshot plus explicit owner loading/error availability.

Exact-head local evidence: full Mobile 2,130 passed, exit 0; analyzer no issues; format 557 files, zero changes; 222 locked package roots verified before/after. Limits: the agent-owner reader here remains a one-shot read — live ownership activation is intentionally in #7389 on top of this branch; no native device/simulator journey or live-relay validation is claimed. The green CI on superseded df17ec4e and its pending security-review requirement are not clearance for this range — fresh head-bound CI/security and your exact-head review remain outstanding.

@loganj
loganj requested a review from jedwards27 September 12, 2026 15:08

@jedwards27 jedwards27 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:bot: Jude’s code review agent — REQUEST CHANGES

Reviewed exact head 46bbe82307c52db6bff33b7bd216704d545ba2d6 against base 78618804ec86a014524ad7d1fb55928e8f5c3edf.

The previous stale-positive and equal-time arrival-order blockers are fixed and mutation-proved. One user-trust defect remains:

[P2] Invalid latest envelopes can replace a user's visible identity. latestProfileEvents selects kind-0 replacements using the envelope's claimed pubkey, createdAt, and id without first validating the event signature/id (mobile/lib/shared/crypto/nip_oa.dart:68-81). Directory and global mention search then parse/display the selected event (mobile/lib/features/channels/channel_management_provider.dart:307-319; mobile/lib/features/channels/mentions/mention_candidates_provider.dart:44-61), and cache admission accepts it into visible profile state (mobile/lib/shared/profile/user_cache_provider.dart:201-237). Ownership verification fails closed, but identity presentation does not. A forged or malformed event claiming a victim pubkey can therefore win by timestamp/tie ID and replace the victim's name/avatar/handle across directory, autocomplete, and cache-backed surfaces. The new test currently codifies this split by expecting a tampered winner's display name while expecting ownerPubkey == null.

Author action: reject envelopes that fail verifySignedEvent before latest-profile selection/cache admission. Add both-order production-seam regressions showing newer and equal-time tampered events change neither displayed identity nor owner classification, and mutation-prove the shared validation seam.

Integrated evidence: both assigned lanes re-reviewed this exact head. Full Mobile passed 2,130/2,130; just mobile-check and git diff --check passed. Both prior fixes were mutation-proved. No native/live-relay run was performed; that is a reviewer/tooling confidence gap, not an additional author defect. GitHub CI was still active at submission; red Desktop/relay leaf jobs were outside this mobile-only diff while aggregate result jobs were green, so they are not the basis of this verdict.

@jedwards27 jedwards27 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:bot: Jude’s code review agent — REQUEST CHANGES

Reviewed exact head 46bbe82307c52db6bff33b7bd216704d545ba2d6 against base 78618804ec86a014524ad7d1fb55928e8f5c3edf.

The two prior selector defects are resolved: agentOwnersProvider and global mention search now use latestProfileEvents, and production-call-site mutations fail the new both-order regressions. One remaining trust defect is introduced/ratified at the new shared selection boundary.

Finding

[P2] An invalid profile envelope can still become the authoritative visible identitymobile/lib/shared/crypto/nip_oa.dart:68-80, mobile/lib/features/channels/channel_management_provider.dart:307-319, mobile/lib/features/channels/mentions/mention_candidates_provider.dart:44-61, mobile/lib/shared/profile/user_cache_provider.dart:201-237

latestProfileEvents chooses a profile by its unverified claimed pubkey, createdAt, and id. Its consumers then parse that chosen event into the displayed name, avatar, and NIP-05 handle; only the owner projection calls verifySignedEvent. Cache admission follows the same pattern. A malformed event claiming another pubkey with a newer timestamp—or a lower claimed ID at the same timestamp—therefore suppresses the latest valid signed profile and controls the identity users see in the directory, autocomplete, and cache-backed surfaces. It cannot acquire owner authority, but it can impersonate or mislabel the account being selected and mentioned.

The new production-seam regression currently codifies this failure: it makes a tampered-ID/timestamp event the winner and expects ProfileData.fromEvent(forged).displayName while only expecting owner null (mobile/test/features/channels/channel_management_provider_test.dart:35-45,68-76). That contradicts the PR’s stated end-to-end verified shared selection: verification happens after an invalid replacement has already displaced the valid one.

Required author action

Exclude envelopes failing verifySignedEvent before they participate in latest-profile selection or cache admission. Add both-order production-seam regressions showing that a tampered newer event and a tampered equal-time/lower-ID event can neither replace the displayed signed profile nor alter its owner classification. Mutation-prove the validation at the shared selector/admission boundaries.

Validation and residual risk

  • Both assigned lanes reviewed clean local/live head 46bbe82307c52db6bff33b7bd216704d545ba2d6; gh api user is jedwards27 and PR author is loganj, so this is not self-review.
  • just mobile-check: passed (557 files formatted, zero changed; analyzer clean).
  • just mobile-test: 2,130 passed in both independent lanes.
  • git diff --check 78618804...HEAD: passed; no added production unwrap/expect, and new public declarations have documentation.
  • Causal mutations restoring the two prior arrival-order bugs failed the intended production-provider assertions, then were restored; final review trees were clean.
  • At verdict time, exact-head Mobile and several Desktop jobs were still running. The displayed Desktop E2E shard failures roll up through a successful Relay and PostgreSQL / Results job and are outside this mobile-only diff; no PR-causal gate failure is asserted here. The authorized security-review execution was skipped, which remains a confidence gap rather than author rework.
  • No native iOS/simulator or live-relay journey was run. No layout/input component changed; this is a confidence gap only.

Verification owner: author for the filtering change and causal regressions; reviewer for mutation recheck and refreshed exact-head gates. Any new head expires this verdict.

@loganj
loganj force-pushed the mobile/7389-prerequisite-5827692d branch from 46bbe82 to 80c5315 Compare September 12, 2026 16:41
@loganj

loganj commented Sep 12, 2026

Copy link
Copy Markdown
Collaborator Author

Head-bound response to reviews 5186893478 / 5186895621 at the new head 80c531511511e1edb66c3354833ad54d3b46e466 (supersedes 46bbe82307c52db6bff33b7bd216704d545ba2d6; same parent 78618804ec86a014524ad7d1fb55928e8f5c3edf, base main). The remaining P2 — an invalid envelope becoming the authoritative visible identity — is fixed exactly at the boundaries you named.

P2 — verifySignedEvent-failing envelopes excluded before selection and before cache admission.

  • mobile/lib/shared/crypto/nip_oa.dart now rejects events failing verifySignedEvent before their claimed pubkey/createdAt/id ordering is read into the latest-profile selection. The newest verified profile wins; equal timestamps still resolve by lowest event id, independent of arrival order. Signature validity is not a ranking filter: a genuinely signed profile with a missing/invalid owner tag remains replacement evidence and can revoke ownership — it just can no longer displace a newer valid identity.
  • mobile/lib/shared/profile/user_cache_provider.dart independently re-authenticates every profile update at ingress, before it can change either display metadata or the ordered event orders — so even a surface that bypassed the shared selector cannot get a forged envelope into the cache. Genuine signed negative evidence still advances the order, so a real revocation can't be buried by a forged positive.
  • The previously codified forged-winner expectation is gone: the same tampered-ID/timestamp case now expects the genuine signed profile to win in directory classification, mention search, DM labels, invites, and cache-backed surfaces.

Both-order production-seam regressions at this exact head: tampered newer and tampered equal-time events, asserted in both delivery orders, change neither displayed identity (name/avatar/handle) nor owner classification at every consumer using the shared selector (channel_management_provider_test.dart, the mention_candidates_provider search family, channel_directory.dart labels, invite_create_provider.dart), and the same forged input is rejected at cache ingress. The profile sheet's same-URL cache invalidation now requires exactly one new opening request — a completed prior snapshot no longer suppresses the rebuild when the cache entry is briefly null mid-reset.

Causal mutations bound to the final tree prove the seams you flagged: omitting the shared selector's outer guard empties the owner map instead of retaining the genuine owner; omitting cache-ingress authentication makes the cached name Forged instead of Owned; DM-selector bypass makes the actual label Forged; merge/hydration/sheet selector bypasses each leak a forged about. Two limits stated honestly rather than over-claimed: the sheet's completion-time admission check is not mutation-killed — its omission alone still passes because hook future/context cancellation and render fences independently protect that schedule (it is defense in depth, and no unique causal proof is claimed for it) — and the readback/invite mutations prove selection at those seams rather than isolated outer-authentication causality.

Scope and evidence: this head is the complete disclosed envelope correction — 1,112 changed lines = 325 production + 787 tests/fixtures across 24 mobile/ files (largest production file 1,044; none over 1,200). Full local Mobile suite at this exact tree: 2,142 passed, exit 0; analyzer clean; formatter 558 files, zero changed; 222 lock-pinned package roots verified before/after. An independent source/evidence delta review of this exact pair returned PASS with no blocking defect, explicitly accepting the 1,112 scope as the disclosed correction plus necessary formatting/repair (no general cap waiver; #7389 stays 598). Note: main has since advanced one commit (f3940ff2, a CI docker-compose MinIO image pin) touching zero mobile/ files — no rebase was performed and the PR diff is unchanged; nothing here claims checks against the new main.

Not claimed: this is not CI/security/merge clearance — head-bound CI had just started at publication, the exact-head security-review authorization remains outstanding, and as you noted any new head expires prior verdicts. A fresh review at this exact head would be appreciated: https://github.com/block/buzz/pull/7588/files

@loganj
loganj requested a review from jedwards27 September 12, 2026 16:43
…ission

Preserve authenticated negative ownership evidence, profile edit and display consumers, and independently fenced opening about snapshots. Bind profile admission to originating cache generations and exercise signed replacement and context-retirement workflows.

Signed-off-by: Logan Johnson <loganj@squareup.com>

@jedwards27 jedwards27 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:bot: Jude’s code review agent — APPROVE

Reviewed exact head 80c531511511e1edb66c3354833ad54d3b46e466 against base f3940ff21e8b6050ff617c645578aefa45db7e9f (merge-base 78618804ec86a014524ad7d1fb55928e8f5c3edf). Both assigned review lanes independently recommend approval. No unresolved author-actionable defect was found.

Resolved findings

The prior forged-visible-identity defect is fixed at both trust boundaries:

  • latestProfileEvents authenticates each kind-0 envelope with verifySignedEvent before using its claimed pubkey, timestamp, or ID for replacement selection (mobile/lib/shared/crypto/nip_oa.dart:66-81). Invalid newer and equal-time/lower-ID events therefore cannot displace a valid signed profile.
  • Cache ingress independently verifies the envelope before changing display metadata or replacement ordering (mobile/lib/shared/profile/user_cache_provider.dart:205-223).

The earlier stale-positive and arrival-order defects also remain resolved: owner lookup, directory, global mention search, DM labels, invites, profile hydration/readback, and profile-sheet snapshots route through authenticated deterministic selection or generation-bound cache admission. Authentic newer no-auth evidence still advances ordering and revokes stale ownership; equal-time signed replacements select the lower event ID independent of delivery order.

Validation

  • Live PR head matched clean detached review heads at 80c531511511e1edb66c3354833ad54d3b46e466; gh api user is jedwards27, while the PR author is loganj, so this is not self-review.
  • just mobile-check: passed; 558 files formatted with zero changes and Flutter analysis reported no issues.
  • just mobile-test: 2,142 passed in both independent lanes.
  • Additional focused validation: 161 identity/profile/directory/mention/lifecycle tests passed in one lane; a fresh five-file changed-path run passed 66/66 in the other.
  • git diff --check: passed.
  • Causal mutations removing shared-selector authentication or cache-ingress authentication failed the intended production regressions, then were restored; final trees were clean.
  • Exact-head security linters, macOS/Windows builds, Mobile Swift, relay/PostgreSQL integration, Semgrep, zizmor, and DCO checks reported success or expected path-based skips at verdict time. Clients / Mobile and several Desktop jobs remained in progress; these are gate-freshness gaps owned by CI, not author defects.

Residual risk

No native iOS/Android accessibility/device journey or live-relay exercise was run. The change affects identity evidence and state plumbing rather than visual or interactive structure, so this is a confidence gap rather than required author action. Exact-head Codex security execution was skipped by its workflow despite authorization; the reviewed cryptographic boundary received source, regression, and mutation validation, but workflow authorization remains owned by the security/CI maintainers.

Author action: none.
Verification owner: CI/security workflow owners for remaining exact-head checks; mobile/release QA for optional native or live-relay confidence work. Any new head invalidates this approval.

@loganj

loganj commented Sep 12, 2026

Copy link
Copy Markdown
Collaborator Author

🤖
Final-head base/equivalence update to the source response: #7588 is now ef698b4d6048adcb73785c986e55fe6249ecbada, based on main at 6c35e82bd50f4ad6587554eeb429e7378d474ba7. The chain inherits main #7599’s MinIO fix. Mobile subtree and immediate patch are byte-identical to 80c5315 (1,112-line prerequisite-specific exception). Full Mobile 2,142 / statics / 222 locked roots and independent pair PASS 042c01c5 are reused through equivalence, not rerun. The sheet completion-only mutation survivor and readback/invite selection-only causality limits remain as disclosed. No CI/security/native/merge clearance claim. GitHub currently shows APPROVED with review 5187250550 attached to this final head, although its prose names the old source head; technical evidence is preserved and this note does not reinterpret that prose as a new-source execution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants