Repository navigation
RespondKit 0.6.2: no email-ask flash, Android attach icon, catalog strings - #56
Conversation
SwiftPM resources must live inside the target path, so the generator now writes RespondKit.xcstrings to RespondKitUI/Resources and Package.swift processes it with defaultLocalization en. localization:check still covers both outputs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t lookup Fails today: the screen shows the ask while a stored email is still being fetched. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
asksForEmail turns true only after the session's contact lookup finds no email, and resets on updateIdentity. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A MutationObserver records every mounted prompt while a host-supplied context changes and when the server already stores an address. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…he catalog asksForEmail is true only once the contact lookup for the current identity found no email. The empty state, Ask us anything and the attach menu read the RespondKit table from the module bundle. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…h, shared strings - The attach control is a 44dp paperclip IconButton in the composer row, left of the field and aligned with send; the menu stays anchored to it. - SupportState.asksForEmail replaces the emailAddress null check. - Compose takes its strings from localization/generated/android/res and drops its own strings.xml; the empty state, subtitle and attach menu use stringResource. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every package at 0.6.2 (Android reads VERSION, SwiftPM uses v0.6.2); docs/releases/0.6.2.md. Not published. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…dy sent Fails today with 'That message is not an agent draft in this support thread.' for the reply's available_audit Discord message. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nt draft' /approve (Discord id or msg_agent id) and the Approve/Reject draft commands look up the reply's available_audit projection; an agent message available to the customer answers with when it was sent and points to /reply. Other ids keep 'not an agent draft'. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
simon-langoustine
left a comment
There was a problem hiding this comment.
VERDICT changes-requested / verifier-failed at head 1de16ef23a576e9b0eab1ba86e0ff191f01b5854, compared with fixed base cd38add8d98719db3c626fce74a0bc0716e7b2fe.
Four act-on findings are detailed in the inline threads:
- Failed contact lookups mark the email as resolved and show the ask even when the server stores an address. Healthy refreshes do not retry the lookup. Reproduced with the actual RN store/API client and in the Android example.
- Canceling the first native contact lookup leaves
contactResolvedfalse behind a cached session. Reopening and refreshing never resolves it, so customers without email never see the ask. Reproduced against unchanged Swift sources; Android has the same sequence. - The specified web/RN empty-state, subtitle and attachment strings still bypass the shared localization toolchain. Only English currently ships, so additional languages are not required; removing the named literals is required.
- The Swift catalog moved, but the macOS localization workflow still compiles its deleted path. The command fails locally and in this head's CI.
Verification passed locally: pnpm exec vp check; pnpm test:all with 406 tests; localization:check; test:release with 8 tests; release:check; swift test with 21 tests; Android core tests, Compose release build/lint/instrumentation build and example debug build; all 6 connected Compose tests; iOS example simulator build. Version wiring is consistent at 0.6.2. The excluded API and Discord source files are unchanged.
Live UI: drove Android's empty state, paperclip menu, system Files picker and selected-file row, and reproduced the contact-error behavior. Drove web sending, close/reopen, a second send at 390x844, file-upload failure/removal and email-save failure. Android layout looks aligned. Local fixtures were used; no customer-facing sends occurred. The attachment fixture returned a precompleted upload, so this is not proof of real file transfer.
Consider: verify-npm also fails because its smoke installation combines React 19.2.8 with automatically selected React Native 0.88.0, which requires React ^19.3.0. The checker and peer constraints are unchanged here; resolve or track this before publishing.
Noted / limits: interactive iOS testing was blocked by simulator launch delays and an agent-device XCTest runner timeout. RN UI and ReceiptGenie host integration were not run. CONTEXT.md, the project verify skill and feature map were absent; used the native demo instructions and independent consistency reviewers. Interrogate's configured Claude/Grok models were unavailable, so GPT-6.1 Sol and GPT-6 Astra reviewed independently; both identified cancellation and localization issues. No product code was edited, pushed, merged or published.
Evidence is attached to RK-2: logs and runnable reproductions, Android layout, attach menu, selected file, incorrect ask after recovery, and web narrow-screen second send. Board links require access to the local Office instance.
The macOS job still pointed at localization/generated/ios, which the catalog move deleted. It now compiles RespondKitUI/Resources and runs when that catalog changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A failed lookup must keep the ask hidden and retry on the next request, and a lookup canceled behind a cached session must resume. Fails today: both mark the contact resolved or never retry it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ached session validToken/token now runs resolveContact for cached and new sessions alike. A failed or interrupted lookup leaves the contact unknown, so the ask stays hidden and the next request retries it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
compileJavaScriptMessages validates through parseResources like the native exporters and emits messages(locale) with typed functions and Intl plural selection, falling back to the closest shipped locale. The generator writes it into both packages; localization:check covers it, format ignores it, and the npm files lists ship it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…catalog Web picks by context.locale, React Native by the device locale. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
simon-langoustine
left a comment
There was a problem hiding this comment.
VERDICT changes-requested / verifier-failed at head c653a6c9643a28701a7ab549e2bb3445b45b3c39.
Re-review is limited to the four findings from 1de16ef and the stated iOS/RN UI gaps. The four original findings are addressed:
- Failed contact lookup keeps the ask hidden and retries on a cached session.
- Canceled native lookup resumes on subsequent use; new regression tests cover it.
- The named web/RN strings now consume generated canonical catalogs; generation checks and package file lists cover them.
- The Apple localization workflow uses the moved catalog. Its compile/runtime check passed locally, and macOS CI passes.
One new act-on issue in the retry fix blocks approval: a failed contact lookup skips the identity-generation check before an API write. Both independent reviewers found this. Using the actual RN store and API client, I reproduced a queued message POST to user A's existing thread with A's token after updateIdentity(B), before logout. The same reproduction produces 1 stale write on this head and 0 on the previous head. A second reproduction shows saveContact after the switch. Swift and Kotlin contain the same unchecked failure return. The inline thread identifies the fix and required test.
The previous iOS/RN execution gaps are now closed for the local demo flows:
- iOS: built this head and used the working agent-device runner. Checked empty state, email ask after lookup, attach menu, system Files picker/cancel, send/reply, close/reopen through the alternate host trigger, and save-email prompt dismissal. With contact returning 503, the ask remained hidden; changing the fixture to a successful empty contact made it appear on a later poll without resetting the store.
- RN Android: built this head, used its Metro bundle, sent
RK2, received the demo reply, opened the catalog-backed attach alert and system Files picker. The demo's custom greeting replaces its no-greeting empty state; that branch was checked in code and catalog tests. - Web: sent a message, checked the catalog-backed subtitle/attach label, reopened, and checked 390x844 layout.
Passed locally: vp check; all 409 package tests; localization:check; 23 Swift tests; 23 Android core tests; Compose release build/lint and example debug build; native iOS simulator build; RN Android debug build; Apple catalog compile/runtime tests. Standard suites do not cover the newly reproduced rejected-lookup identity race.
Consider: the unchanged npm smoke peer-dependency conflict still fails verify-npm. No new act-on finding beyond the identity race. No ReceiptGenie host integration or real file-transfer check; all sends used local fixtures. Android multiword input was truncated by the adapter, so only the actual RK2 send is claimed. No product source changes, push, merge or publication.
Evidence on RK-2: logs and runnable head/baseline reproductions, iOS attach menu, iOS send/reply, failed contact hidden, recovered contact ask, RN send/reply, RN attach menu, web narrow layout. Board links require the local Office instance.
…ing from the old session Fails at c653a6c: the failed lookup returns before the epoch check, so the old identity's token reaches the next request (RN saveContact, Swift/Kotlin statuses). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
resolveContact can return early on a failed lookup, so token/validToken now checks the epoch before handing out the session token. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
simon-langoustine
left a comment
There was a problem hiding this comment.
Approved at 1c7f1816ef84d0e19aca60eab5aafc3ee34381f4 — unit-test-verified.
Scoped re-review of the remaining P1 identity race, from fixed point c653a6c9643a28701a7ab549e2bb3445b45b3c39.
The RN, Swift, and Kotlin token paths now recheck the identity epoch immediately after resolving contact, before returning the token to an authorized operation. A failed contact request can no longer let the old identity perform the pending operation after an identity switch. The new regression tests cover this interruption. Both independent reviewers found no remaining issue in this six-file delta.
Act-on: none. The remaining P1 is resolved; the four original findings were resolved in the preceding review.
Verification at this head:
- React Native: 20 tests passed.
- Swift: 24 tests passed.
- Kotlin core: 24 tests passed.
pnpm exec vp check: passed.- Both prior adversarial reproductions rerun against current source: zero stale message writes and zero stale contact saves after switching identity. Logout of the old session still occurs as intended.
Consider: the existing verify-npm smoke-install failure remains a pre-publication issue (React 19.2.8 / automatically selected RN 0.88 peer conflict), outside this scoped logic fix. Current failing job.
Noted: unchanged screens were not driven again at this head. The preceding review closed the iOS adapter and RN UI gaps at c653a6c9643a28701a7ab549e2bb3445b45b3c39; that review records the UI coverage and limits. This approval is for the scoped pure-logic follow-up, not a store-release or publication verdict. No product code edits, merge, or publication performed.
Evidence: RK-2 logs and standalone reproductions (Office board access required).
The smoke project named no react-native, so npm picked the newest release in the >=0.81 peer range. react-native 0.88.0 needs react ^19.3.0 and the install failed with ERESOLVE against the pinned 19.2.8, blocking verify-npm and publish-npm. Install the versions the SDK is built and tested with (0.87.1 and its locked companions). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Why
Simon tested RespondKit 0.6.1 in ReceiptGenie's iOS and Android apps and found three problems (RK-1):
ReceiptGenie 2.9.0 should ship on the fixed SDK.
What changed
asksForEmailon the iOS store, AndroidSupportStateand the RN snapshot): the ask shows only after the contact lookup for the current identity has succeeded without finding an email. A host-supplied email counts as known immediately, andupdateIdentityresets the state. A failed or canceled lookup keeps the ask hidden, andresolveContactretries it on the next request, including when the session is cached (review findings 1–2). The epoch is rechecked after that step, so an identity switch during a failed lookup can't leak the old session's token (follow-up P1). Before, iOS, Android and RN rendered the ask onemail == nilwhile a stored contact was still being fetched.resolving_contextwhenever the context doesn't match and sets the email beforeready. Two MutationObserver tests now guard this; I confirmed they fail when the prompt does mount.IconButtonin the composer row, left of the field and aligned with send. The photo/files menu stays anchored to it.RespondKit.xcstringsintoRespondKitUI/Resources(defaultLocalization: "en",.process("Resources")).localization/generated/android/resas a res dir and drops its ownstrings.xml.compileJavaScriptMessages(in@respondkit/paraglide-resources, validated by the sameparseResources) emits a typedmessages(locale)module intopackages/react/src/widget/messages.tsandpackages/react-native/src/messages.ts.localization:checkbyte-checks both, and the npmfileslists ship them.context.locale, RN by the device locale.pnpm version:set 0.6.2anddocs/releases/0.6.2.md. Not published, and no GitHub release.Scope
settings.jsonhaslocales: ["en"]), so "every shipped locale" meansen. This PR adds no new languages. Translating into ReceiptGenie's languages needs a decision and a follow-up.settings.json, at build time.Tradeoffs
strings.xmlwas deleted rather than kept in parallel, because duplicate resource names in one module fail the merge.Blast radius
respondkit_newis removed (userespondkit_new_conversation), andrespondkit_intronow holds the longer intro line. Hosts that override either name must update their overrides. ReceiptGenie doesn't.AttachmentPicker(internal) now takes a content slot.MessageComposer(web) takes an optionallocale.package.jsonadds the@respondkit/paraglide-resourcesworkspace devDependency; the lockfile change is 3 lines.RespondKitUItarget now has a resource bundle.apps/apiandpackages/discorddiffs are the 0.6.2 version bumps;/approveand the Discord commands are untouched (a separate PR redesigns them).Verification
pnpm exec vp checkpasses.pnpm localization:checkmatches.pnpm test:releasepasses.pnpm test:allpasses: 410 tests at 1c7f181 (paraglide-resources 37 with the new exporter test, react-native 20 with the retry and identity-race cases, API 159).swift test: 24 tests in 3 suites, including the failed-lookup (2 cases), canceled-lookup and identity-switch-during-failed-lookup tests; each fails on the store before its fix. The iOS simulator build of RespondKitUI succeeds, and the built bundle containsen.lproj/RespondKit.stringswith all six keys../gradlew :core:test :compose:assembleRelease :compose:lint :compose:assembleAndroidTest: BUILD SUCCESSFUL, with 24 core tests including the failed, canceled and identity-switch lookup tests. The identity-switch test fails at c653a6c with 1 stale statuses call.:compose:connectedDebugAndroidTeston an API 36 emulator: 6/6, including the newattachIconSitsLeftOfTheMessageFieldInTheSendRow.native/examples/demo_server.pyare attached to RK-1 on the board:verify-npm. The smoke install now pins the React Native peers to the tested versions (react-native 0.87.1, device-info 15.0.2, get-random-values 2.0.0, safe-area-context 5.10.1). Before, it resolved react-native 0.88.0, which needs react ^19.3.0 and failed with ERESOLVE against the pinned 19.2.8.npm pack --dry-runincludessrc/widget/messages.ts(react) andsrc/messages.ts(react-native).simctlcan't tap), and no on-device check inside ReceiptGenie itself.🤖 Generated with Claude Code