Repository navigation
Inbox mobile: guided reviews in the iPhone app (M4) - #1790
Merged
Merged
Conversation
backnotprop
force-pushed
the
feat/mobile-m4-guides
branch
6 times, most recently
from
October 8, 2026 20:00
0104723 to
1373a4b
Compare
A guide's tile in the thread opens a full-screen cover on the bundled surface
(6.1, 6.2): the sections with their reviewed ticks and Continue, one section
per screen with Previous, Reviewed and Next. The bar is the shell's: its title
follows the surface's section messages ("02 of 04"), close turns into back,
and the wrap button sends the new set_wrap. Each tick is saved through the
device door (7.20) and shows in the desktop window.
Dynamic Type reaches the guide's section card through text-size-adjust (iOS
WebKit ignores zoom for letters); the card's layout zoom and the controls at
the thumb stop at the largest non-accessibility size, and the guide's title
grows by points, not by a factor. The proof sends a shipped ledger-export
guide through submit_guide and marks two sections reviewed on the phone.
…fs in the system monospace, the phone's diff header, no collapse on the only section, guide-viewer in the CI paths)
backnotprop
force-pushed
the
feat/mobile-m4-guides
branch
from
October 9, 2026 01:36
1373a4b to
03affd5
Compare
1 task
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #1785 (M2,
feat/mobile-m2-attachments, rebased onto its head 2eb4480). M4 needs M2's surface host (SurfaceHost.swift, the two schemes, the main-frame message rule, the touch window). Retarget tomainwhen M2 merges; I rebase once then.The review's fixes (REVIEW-PLANNOTATOR-MOBILE-M4-2026-10-08, one round)
saveTicksnow keeps the ticks the Inbox last confirmed while taps are in flight. When a save fails, the thread is read again. If the computer cannot answer that either, the phone goes back to the confirmed ticks and hands them to the surface, so Reviewed reads off again. A successful save writes the Inbox's answer when it is the last tap in flight (review item 5). The alert is "Not saved" with the error's own words, not the two sentences that said the same thing. Proof step: on section 03 with the proxydown, Reviewed is tapped, "Not saved" shows (frame6.2-not-saved), and after OK Reviewed reads off (value 0) while the Inbox still keepstrue,true,false,false..sf-gcardsets--diffs-font-family: var(--font-mono)(the surface'sui-monospacelist). The renderer's own list reached Courier New on iOS. The variable crosses the renderer's shadow root. Frames6.2light and dark show the system monospace..sf-gcard button[aria-label="Collapse section"]): on a one-section screen it collapsed the only content, and it was a 32 pt target. The diff header uses the review app's own phone layout (compactTouchLayout, passed by the surface's guide reader throughgetDiffRendererProps;ReadOnlyDiffaccepts the prop). It shows the whole path, puts its ellipsis at the leading edge only when the path does not fit, and has a 44 pt header and toggle. One CSS rule starts a path that fits at the left. Plannotator's components are unchanged.ios.ymlpaths gainpackages/guide-viewer/**.The story
An agent's guided review now opens on the phone. The thread shows the guide as a tile. A tap opens Plannotator's guide viewer full screen: the sections with their reviewed marks and Continue (6.1), then one section per screen, with its diffs unified and wrapped and Previous, Reviewed and Next at the thumb (6.2). The app's bar follows the guide ("02 of 04", close becomes back). Each Reviewed tick is saved through the device door and shows in the desktop window. The guide's text follows Dynamic Type. The section card did not follow it before this PR.
What changed
apps/ios/Plannotator/Guides/GuideCover.swift(new): the full-screen cover on M2's warm web view. It loadsGET messages/:id/guide(7.19) and sendsset_appearance,set_wrapandopen_guidewith the ticks kept on the message. It readsreviewed(selection haptic, then a save through the door) andsection(title, back, a VoiceOver screen change). Back sendsopen_sectionnull. The wrap button sendsset_wrap. Loading, error with Try Again, links through M2's https/mailto rule, a reload after the web process ends.apps/ios/Plannotator/Attachments/AttachmentTiles.swift,Thread/ThreadScreen.swift: the guide's tile (the tinted book mark; "Guided review: <title>"; "4 sections, 6 files, +70 −14"). It counts in "N attachments", as 8.1 draws it.apps/ios/Plannotator/Attachments/SurfaceHost.swift: thereviewedandsectionevents;OpenGuide,OpenSectionandSetWrap;sendAppearanceshared by both covers (moved out ofAttachmentCover.swift).apps/ios/Plannotator/App/SourceSession.swift:saveTicks. A tick shows at once. Ticks on one guide go out one after another, each with every section's tick, so the last tap wins. When a tick is refused or cannot reach the computer, the thread is read again, an alert says "Not saved", and the surface gets back the ticks the Inbox keeps.apps/ios/PlannotatorKit/Sources/PlannotatorKit/Guides.swift(new),Models.swift:guide(message:)andsaveGuideReviewed(7.20). The message gainsguideandguide_reviewed. The snapshot stays opaque JSON for the surface.packages/core/inbox-surface-bridge.ts,packages/inbox/surface/SurfaceApp.tsx:set_wrap(shell to surface) sets Plannotator'sdiffOverflow(wraporscroll). The read-only diff renderer already follows that setting.packages/inbox/surface/surface.css: Dynamic Type for the guide (below).adr/implementation/inbox-mobile.mdsection 5: theset_wraprow and its reason, edited first.apps/ios/PlannotatorUITests/GuideProofTests.swift(new);apps/ios/scripts/proof.ts(/guidesends the fixture throughsubmit_guide;/guide-ticksreads the ticks through the window's ownGET /api/inbox/threads/:id); fixtureapps/ios/scripts/fixtures/ledger-export.guide.json+.patch(the record's "Stream ledger exports" guide, four sections, six files, made from a realgit diff)..github/workflows/ios.yml: paths gainpackages/inbox/guide/**(the surface's guide reader).AGENTS.mdInbox section andapps/ios/README.md: M4 written in.Dynamic Type on the guide (the spike's finding, left to M4 by M2)
iOS WebKit lays out a
zoomed box larger but keeps its letters at their own size. The section card (.sf-gcard) now also takes-webkit-text-size-adjust(--sf-guide-adjust, set with--sf-text-adjustonset_appearance), as M2 did for documents. Desktop WebKit ignores that property. Seen at the largest size, three more changes in the same file:Record sections made real
6.1,6.1-two-reviewed).6.2,6.2-reviewed,6.2-unwrapped).8.1-guide-tile).research/operational/mobile-proofs/M4-2026-10-08/compare/(record left, built right). Recording:M4-guide-flow.mp4. Frames at the largest Dynamic Type size:ax-6.1,ax-6.2.Proofs
bun apps/ios/scripts/proof.ts --binary <compiled plannotator> --only PlannotatorUITests/GuideProofTests, on a fresh iPhone 17 simulator (iOS 26.5), againstplannotator inbox --backgroundunder a temp data dir:submit_guidethrough the MCP SDK's stdio client (scripts/inbox-sim.ts).true,false,false,false, thentrue,true,false,false.proof.tswith no--only: pairing and answering, attachments, the guide) on this head, rebased onto M2 at 2eb4480, with the review's fixes: 3 of 3 pass (pairing and answering 255 s, attachments 241 s, guide 106 s). The guide loads nothing from the network and opens as before under M2's rule list. Log:research/operational/mobile-proofs/M4-2026-10-08/proof-run-all-flows.login the Workspaces meta repo.tests/e2e/surface.spec.ts(Playwright WebKit, compiled binary): 9 of 9 pass. This includes S1's guide test and the theme and text-size test.Gates run
bun run typecheck;bun test tests/entry-assets.test.ts tests/favicon-surfaces.test.ts packages/core(348 pass) under a temp data dir;bun run --cwd packages/ui smoke:package(core changed);bun run check:release-version; the surface Playwright spec;xcodegen generateleaves no diff;gitleaks git . --config .gitleaks.toml --log-opts="origin/feat/mobile-m2-attachments..HEAD": no leaks. The guide chain is untouched (only the surface's ownsf-CSS), so the guides.show manifest is unchanged.Deviations from the record and the contract, with reasons
createGuideHtmlin the surface. An empty menu is worse than none, so the trailing slot is blank and the title stays centred. Follow-up if the owner wants Share there.GuideSectionCard, as S1 mounted it, with its card chrome, "02 / 04" and the grouped background. The record draws a bare title on the plain screen. The record's rule is Plannotator's components as they are, and the review agreed. The rough edges on a phone are fixed in the surface's CSS (the chevron is not drawn, the header uses the compact layout, the diff is in the system monospace).set_wrapadded to section 5 (reason above). This is the only shape change.Limits
None.
Leaves out
Comments on diff lines (owner decision 5); everything in later steps. Follow-ups from the review: swipe down to close for both covers (item 2); a dropped connection reads as "Your computer sent an answer this app can't read. Update Plannotator on both", M1's error mapping (item 3); the proof's wrap step asserts the shell button, not what the surface drew (item 6); raw
<img src>in guide prose is auto-linked by Plannotator's inline markdown, inert on the phone (item 7, for the guide-viewer owners).