Skip to content

State restoration and continuity across devices - #5663

Open
shai-almog wants to merge 124 commits into
masterfrom
feature/state-restoration-continuity
Open

State restoration and continuity across devices#5663
shai-almog wants to merge 124 commits into
masterfrom
feature/state-restoration-continuity

Conversation

@shai-almog

Copy link
Copy Markdown
Collaborator

What this is

A Codename One app that the operating system kills comes back to its first screen. Lifecycle.stop() kept the current Form in a plain field, so a suspend and resume looked right and a reclaimed process lost everything -- which on Android is the ordinary outcome of a few minutes in another app.

com.codename1.continuity saves what the user was doing and brings it back, and on Apple platforms offers that same work to the other devices the person is signed in to.

The substrate was already here and unused: com.codename1.router keeps a stack of deep-link paths, which is exactly a serializable, portable "where the user is". Navigation.restoreStack rebuilds it without animating through every screen on the way.

Two packages, because they cost different things

iOS / macOS Android Simulator & desktop JavaScript
Restore after the process is killed yes yes yes yes
Restore the @Route screen stack yes yes yes yes
Carry on where they left off, on a device they're holding yes -- simulated --
A key/value store synced across devices yes -- simulated --
Carry state to any other device your StateRelay your StateRelay your StateRelay your StateRelay

com.codename1.continuity buys a native define and one NSUserActivityTypes entry, and no entitlement. com.codename1.continuity.sync buys the iCloud key-value store, whose entitlement has to be granted on the App ID -- handing that to an app that only wanted to pass work to the tablet in the user's other hand would fail its codesigning for a capability it never asked for. Same split, same reason, as usesSmartHome / usesHomeAccessoryData.

Three decisions worth recording

  • Saving is continuous, not at shutdown. Every navigation schedules a checkpoint written once per event-loop pass. Android's generated activity blocks the platform main thread until the app's stop() returns, so an app that saved there would pay for it on every suspend.
  • Nothing happens until the application opts in. start() is unchanged for every existing app, and restore() is never called for anyone -- where restoration belongs in a launch is a decision only the app can make.
  • Codename One runs no relay server. Continuation between Apple devices is the platform's; everything else goes through a StateRelay against the app's own endpoint, because deciding which saved states belong to the same person is the app's account system's question.

The load-bearing detail

The iOS delegate matches continuity before intents. The intents block ends in a general branch that hands any remaining activity to Java and returns Java's answer, and Intents.dispatchUserActivity correctly declines a type it never declared -- so an app using both would have had its own continuation asked about by the wrong framework, told no, and dropped.

NSUserActivityTypes stays a single key for the same reason a second one is worse than none: iOS reads a duplicated key unpredictably. The two contributors meet in userActivityTypesKey.

Android needs nothing injected -- no permission, no manifest entry, no dependency. The bridge exists there for one job: flushing the checkpoint from onSaveInstanceState, the last callback guaranteed before a background process is reclaimed. Both cross-device capabilities report themselves unsupported rather than being emulated, because an app told "yes" by a bridge that then dropped the state is worse off than one told "no", which can fall back to a relay and reach an iPhone as easily as another Android.

Verification

The load-bearing one: a real Xcode build of the generated project produced one NSUserActivityTypes array carrying both the sample's three App Intent ids and ...hellocodenameone.continuity. BUILD SUCCEEDED for iOS and watchOS, and a deliberate probe inside the #ifdef CN1_USE_CONTINUITY block failed the build, so that check is not vacuous. Dead-code elimination left both native callbacks with real bodies.

Also green locally: 46 core unit tests, 10 plist-merge tests, 7 preflight tests, 5 shipped-hooks tests; SpotBugs 0 findings across core-unittests, android, ios, codenameone-maven-plugin and build-hint-catalog; and the cast-semantics, control-character, copyright, build-hint, snippet and prose gates.

Paired change

The builder half is mirrored in BuildDaemon; that PR has to land with this one.

🤖 Generated with Claude Code

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 2, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-05T13:58:19.994255Z 3de7bc2 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: def44c429d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread CodenameOne/src/com/codename1/continuity/StateCodec.java Outdated
Comment thread CodenameOne/src/com/codename1/continuity/Continuity.java Outdated
Comment thread CodenameOne/src/com/codename1/continuity/Continuity.java
Comment thread CodenameOne/src/com/codename1/continuity/StateCodec.java Outdated
@shai-almog

shai-almog commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 12 screenshots: 12 matched.
✅ JavaSE simulator integration screenshots matched stored baselines.

@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Developer Guide build artifacts are available for download from this workflow run:

Developer Guide quality checks:

  • AsciiDoc linter: No issues found (report)
  • Vale: No alerts found (report)
  • Paragraph capitalization: No paragraph capitalization issues (report)
  • LanguageTool: No grammar matches (report)
  • Image references: No unused images detected (report)

@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

✅ Continuous Quality Report

Test & Coverage

Static Analysis

  • SpotBugs [Report archive]
    • ByteCodeTranslator: 0 findings (no issues)
    • android: 0 findings (no issues)
    • build-hint-catalog: 0 findings (no issues)
    • build-hint-tools: 0 findings (no issues)
    • codenameone-maven-plugin: 0 findings (no issues)
    • core-unittests: 0 findings (no issues)
    • ios: 0 findings (no issues)
  • PMD: 0 findings (no issues) [Report archive]
  • Checkstyle: 0 findings (no issues) [Report archive]

Generated automatically by the PR CI workflow.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e9431117ba

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread CodenameOne/src/com/codename1/continuity/Continuity.java
Comment thread CodenameOne/src/com/codename1/continuity/AppState.java Outdated
Comment thread CodenameOne/src/com/codename1/continuity/Continuity.java Outdated
@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Cloudflare Preview

@shai-almog

shai-almog commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 151 screenshots: 151 matched.

Native Android coverage

  • 📊 Line coverage: 9.21% (9146/99268 lines covered) [HTML preview] (artifact android-coverage-report, jacocoAndroidReport/html/index.html)
    • Other counters: instruction 8.97% (47024/524333), branch 3.53% (1751/49663), complexity 3.51% (1858/52961), method 5.40% (1505/27861), class 10.86% (405/3729)
    • Lowest covered classes
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysKt – 0.00% (0/6367 lines covered)
      • kotlin.collections.unsigned.kotlin.collections.unsigned.UArraysKt___UArraysKt – 0.00% (0/2384 lines covered)
      • org.jacoco.agent.rt.internal_0e20598.asm.org.jacoco.agent.rt.internal_0e20598.asm.ClassReader – 0.00% (0/1524 lines covered)
      • kotlin.collections.kotlin.collections.CollectionsKt___CollectionsKt – 0.00% (0/1187 lines covered)
      • org.jacoco.agent.rt.internal_0e20598.asm.org.jacoco.agent.rt.internal_0e20598.asm.MethodWriter – 0.00% (0/922 lines covered)
      • kotlin.sequences.kotlin.sequences.SequencesKt___SequencesKt – 0.00% (0/736 lines covered)
      • com.google.common.cache.com.google.common.cache.LocalCache$Segment – 0.00% (0/726 lines covered)
      • okio.okio.Buffer – 0.00% (0/687 lines covered)
      • kotlin.text.kotlin.text.StringsKt___StringsKt – 0.00% (0/625 lines covered)
      • org.jacoco.agent.rt.internal_0e20598.asm.org.jacoco.agent.rt.internal_0e20598.asm.Frame – 0.00% (0/570 lines covered)

✅ Native Android screenshot tests passed.

Native Android coverage

  • 📊 Line coverage: 9.21% (9146/99268 lines covered) [HTML preview] (artifact android-coverage-report, jacocoAndroidReport/html/index.html)
    • Other counters: instruction 8.97% (47024/524333), branch 3.53% (1751/49663), complexity 3.51% (1858/52961), method 5.40% (1505/27861), class 10.86% (405/3729)
    • Lowest covered classes
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysKt – 0.00% (0/6367 lines covered)
      • kotlin.collections.unsigned.kotlin.collections.unsigned.UArraysKt___UArraysKt – 0.00% (0/2384 lines covered)
      • org.jacoco.agent.rt.internal_0e20598.asm.org.jacoco.agent.rt.internal_0e20598.asm.ClassReader – 0.00% (0/1524 lines covered)
      • kotlin.collections.kotlin.collections.CollectionsKt___CollectionsKt – 0.00% (0/1187 lines covered)
      • org.jacoco.agent.rt.internal_0e20598.asm.org.jacoco.agent.rt.internal_0e20598.asm.MethodWriter – 0.00% (0/922 lines covered)
      • kotlin.sequences.kotlin.sequences.SequencesKt___SequencesKt – 0.00% (0/736 lines covered)
      • com.google.common.cache.com.google.common.cache.LocalCache$Segment – 0.00% (0/726 lines covered)
      • okio.okio.Buffer – 0.00% (0/687 lines covered)
      • kotlin.text.kotlin.text.StringsKt___StringsKt – 0.00% (0/625 lines covered)
      • org.jacoco.agent.rt.internal_0e20598.asm.org.jacoco.agent.rt.internal_0e20598.asm.Frame – 0.00% (0/570 lines covered)

Benchmark Results

Detailed Performance Metrics

Metric Duration
SIMD kernel backend scalar fallback (no native SIMD)
SIMD int-add (64K x300) java 325ms / native 189ms = 1.7x speedup
SIMD float-mul (64K x300) java 214ms / native 209ms = 1.0x speedup
SIMD kernel correctness PASS (native result == scalar reference)
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 SIMD byte path gated to scalar (CPU autovectorizes scalar; explicit SIMD not beneficial here)
Base64 CN1 encode 91.000 ms
Base64 CN1 decode 86.000 ms
Base64 native encode 334.000 ms
Base64 encode ratio (CN1/native) 0.272x (72.8% faster)
Base64 native decode 287.000 ms
Base64 decode ratio (CN1/native) 0.300x (70.0% faster)
Image encode benchmark status skipped (SIMD unsupported)

@shai-almog

shai-almog commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 166 screenshots: 166 matched.
Native Windows port, REAL shipping pipeline: the hellocodenameone screenshot suite rendered by a binary CROSS-COMPILED on Linux (clang-cl + xwin, WebView2 linked) and RUN on a Windows x64 runner. Compared against the in-repo baseline in scripts/windows/screenshots.

Benchmark Results

Detailed Performance Metrics

Metric Duration
SIMD kernel backend SSE2 (x64) / NEON (arm64) native kernels
SIMD int-add (64K x300) java 62ms / native 4ms = 15.5x speedup
SIMD float-mul (64K x300) java 65ms / native 5ms = 13.0x speedup
SIMD kernel correctness PASS (native result == scalar reference)
Base64 native bridge unavailable (CN1 + SIMD + image benchmarks only)
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 SIMD byte path gated to scalar (CPU autovectorizes scalar; explicit SIMD not beneficial here)
Base64 CN1 encode 199.000 ms
Base64 CN1 decode 133.000 ms
Base64 SIMD encode 101.000 ms
Base64 encode ratio (SIMD/CN1) 0.508x (49.2% faster)
Base64 SIMD decode 98.000 ms
Base64 decode ratio (SIMD/CN1) 0.737x (26.3% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 12.000 ms
Image createMask (SIMD on) 50.000 ms
Image createMask ratio (SIMD on/off) 4.167x (316.7% slower)
Image applyMask (SIMD off) 57.000 ms
Image applyMask (SIMD on) 66.000 ms
Image applyMask ratio (SIMD on/off) 1.158x (15.8% slower)
Image modifyAlpha (SIMD off) 54.000 ms
Image modifyAlpha (SIMD on) 66.000 ms
Image modifyAlpha ratio (SIMD on/off) 1.222x (22.2% slower)
Image modifyAlpha removeColor (SIMD off) 86.000 ms
Image modifyAlpha removeColor (SIMD on) 35.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.407x (59.3% faster)

@shai-almog

shai-almog commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 166 screenshots: 166 matched.
Native Windows port (x64 / Intel-AMD): full hellocodenameone screenshot suite rendered offscreen with Direct2D/DirectWrite, plus the real benchmarks (base64 native/CN1/SIMD, image createMask/applyMask/modifyAlpha/PNG/JPEG, SSE2 SIMD kernels). Compared against the in-repo baseline in scripts/windows/screenshots.

Benchmark Results

Detailed Performance Metrics

Metric Duration
SIMD kernel backend SSE2 (x64) / NEON (arm64) native kernels
SIMD int-add (64K x300) java 83ms / native 5ms = 16.6x speedup
SIMD float-mul (64K x300) java 73ms / native 5ms = 14.6x speedup
SIMD kernel correctness PASS (native result == scalar reference)
Base64 native bridge unavailable (CN1 + SIMD + image benchmarks only)
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 SIMD byte path gated to scalar (CPU autovectorizes scalar; explicit SIMD not beneficial here)
Base64 CN1 encode 193.000 ms
Base64 CN1 decode 140.000 ms
Base64 SIMD encode 102.000 ms
Base64 encode ratio (SIMD/CN1) 0.528x (47.2% faster)
Base64 SIMD decode 103.000 ms
Base64 decode ratio (SIMD/CN1) 0.736x (26.4% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 12.000 ms
Image createMask (SIMD on) 27.000 ms
Image createMask ratio (SIMD on/off) 2.250x (125.0% slower)
Image applyMask (SIMD off) 71.000 ms
Image applyMask (SIMD on) 81.000 ms
Image applyMask ratio (SIMD on/off) 1.141x (14.1% slower)
Image modifyAlpha (SIMD off) 71.000 ms
Image modifyAlpha (SIMD on) 95.000 ms
Image modifyAlpha ratio (SIMD on/off) 1.338x (33.8% slower)
Image modifyAlpha removeColor (SIMD off) 82.000 ms
Image modifyAlpha removeColor (SIMD on) 30.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.366x (63.4% faster)

@shai-almog

shai-almog commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 166 screenshots: 166 matched.
Native Linux port (x64), GTK3/Cairo/Pango, ParparVM bytecode-to-C (no JVM): the hellocodenameone screenshot suite rendered by a native ELF built + run on the GitHub x64 runner. Baseline: scripts/linux/screenshots.

@shai-almog

shai-almog commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 166 screenshots: 166 matched.
Native Linux port (arm64), GTK3/Cairo/Pango, ParparVM bytecode-to-C (no JVM): the hellocodenameone screenshot suite rendered by a native ELF built + run on the GitHub arm64 runner. Baseline: scripts/linux/screenshots-arm.

@shai-almog

shai-almog commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 166 screenshots: 166 matched.
Native Windows port (arm64 / Apple Silicon - Arm): full hellocodenameone screenshot suite rendered offscreen with Direct2D/DirectWrite, plus the real benchmarks (base64 native/CN1/SIMD, image createMask/applyMask/modifyAlpha/PNG/JPEG, NEON SIMD kernels). Compared against the in-repo baseline in scripts/windows/screenshots.

Benchmark Results

Detailed Performance Metrics

Metric Duration
SIMD kernel backend SSE2 (x64) / NEON (arm64) native kernels
SIMD int-add (64K x300) java 57ms / native 3ms = 19.0x speedup
SIMD float-mul (64K x300) java 61ms / native 3ms = 20.3x speedup
SIMD kernel correctness PASS (native result == scalar reference)
Base64 native bridge unavailable (CN1 + SIMD + image benchmarks only)
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 SIMD byte path gated to scalar (CPU autovectorizes scalar; explicit SIMD not beneficial here)
Base64 CN1 encode 266.000 ms
Base64 CN1 decode 157.000 ms
Base64 SIMD encode 65.000 ms
Base64 encode ratio (SIMD/CN1) 0.244x (75.6% faster)
Base64 SIMD decode 63.000 ms
Base64 decode ratio (SIMD/CN1) 0.401x (59.9% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 24.000 ms
Image createMask (SIMD on) 3.000 ms
Image createMask ratio (SIMD on/off) 0.125x (87.5% faster)
Image applyMask (SIMD off) 25.000 ms
Image applyMask (SIMD on) 18.000 ms
Image applyMask ratio (SIMD on/off) 0.720x (28.0% faster)
Image modifyAlpha (SIMD off) 18.000 ms
Image modifyAlpha (SIMD on) 12.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.667x (33.3% faster)
Image modifyAlpha removeColor (SIMD off) 21.000 ms
Image modifyAlpha removeColor (SIMD on) 13.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.619x (38.1% faster)

@shai-almog

shai-almog commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 181 screenshots: 181 matched.
✅ JavaScript-port screenshot tests passed.

@shai-almog

shai-almog commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 160 screenshots: 160 matched.
✅ Native Mac screenshot tests passed.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 276 seconds

Detailed Performance Metrics

Metric Duration
SIMD kernel backend SSE2 (x64) / NEON (arm64) native kernels
SIMD int-add (64K x300) java 62ms / native 3ms = 20.6x speedup
SIMD float-mul (64K x300) java 76ms / native 2ms = 38.0x speedup
SIMD kernel correctness PASS (native result == scalar reference)
Base64 native bridge unavailable (CN1 + SIMD + image benchmarks only)
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 SIMD byte path active (NEON-accelerated)
Base64 CN1 encode 189.000 ms
Base64 CN1 decode 133.000 ms
Image encode benchmark iterations 100
Image createMask (SIMD off) 12.000 ms
Image createMask (SIMD on) 8.000 ms
Image createMask ratio (SIMD on/off) 0.667x (33.3% faster)
Image applyMask (SIMD off) 143.000 ms
Image applyMask (SIMD on) 121.000 ms
Image applyMask ratio (SIMD on/off) 0.846x (15.4% faster)
Image modifyAlpha (SIMD off) 250.000 ms
Image modifyAlpha (SIMD on) 195.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.780x (22.0% faster)
Image modifyAlpha removeColor (SIMD off) 122.000 ms
Image modifyAlpha removeColor (SIMD on) 129.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 1.057x (5.7% slower)

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 85e4b48ba4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread Ports/iOSPort/nativeSources/CodenameOne_GLAppDelegate.m
Comment thread CodenameOne/src/com/codename1/continuity/Continuity.java Outdated
Comment thread CodenameOne/src/com/codename1/continuity/Continuity.java Outdated
Comment thread CodenameOne/src/com/codename1/continuity/sync/SyncedStore.java Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2c5a39af91

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread CodenameOne/src/com/codename1/continuity/Continuity.java
Comment thread CodenameOne/src/com/codename1/continuity/StateCodec.java

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ecf68fc364

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread CodenameOne/src/com/codename1/continuity/Continuity.java Outdated
Comment thread CodenameOne/src/com/codename1/continuity/Continuity.java Outdated
Comment thread CodenameOne/src/com/codename1/continuity/Continuity.java Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 646d895af1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread CodenameOne/src/com/codename1/impl/continuity/LocalContinuityBridge.java Outdated
Comment thread CodenameOne/src/com/codename1/continuity/Continuity.java

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3f2b72c7e5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread CodenameOne/src/com/codename1/continuity/Continuity.java
Comment thread CodenameOne/src/com/codename1/continuity/Continuity.java Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7e121fdcef

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread CodenameOne/src/com/codename1/continuity/Continuity.java

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1185b5b3f2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread CodenameOne/src/com/codename1/router/Navigation.java
Comment thread CodenameOne/src/com/codename1/continuity/Continuity.java
Comment thread CodenameOne/src/com/codename1/continuity/Continuity.java Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5eaf1db562

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread CodenameOne/src/com/codename1/continuity/Continuity.java Outdated
Comment thread CodenameOne/src/com/codename1/continuity/sync/SyncedStore.java Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 34598c5aa2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread CodenameOne/src/com/codename1/continuity/sync/SyncedStore.java Outdated
Comment thread CodenameOne/src/com/codename1/continuity/Continuity.java
Comment thread CodenameOne/src/com/codename1/continuity/AppState.java
@shai-almog

shai-almog commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 143 screenshots: 143 matched.
✅ Native iOS screenshot tests passed.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 1135 seconds

Build and Run Timing

Metric Duration
Simulator Boot 98000 ms
Simulator Boot (Run) 0 ms
App Install 12000 ms
App Launch 10000 ms
Test Execution 473000 ms

Detailed Performance Metrics

Metric Duration
SIMD kernel backend SSE2 (x64) / NEON (arm64) native kernels
SIMD int-add (64K x300) java 73ms / native 7ms = 10.4x speedup
SIMD float-mul (64K x300) java 77ms / native 4ms = 19.2x speedup
SIMD kernel correctness PASS (native result == scalar reference)
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 SIMD byte path active (NEON-accelerated)
Base64 CN1 encode 277.000 ms
Base64 CN1 decode 149.000 ms
Base64 native encode 691.000 ms
Base64 encode ratio (CN1/native) 0.401x (59.9% faster)
Base64 native decode 358.000 ms
Base64 decode ratio (CN1/native) 0.416x (58.4% faster)
Base64 SIMD encode 62.000 ms
Base64 encode ratio (SIMD/CN1) 0.224x (77.6% faster)
Base64 SIMD decode 75.000 ms
Base64 decode ratio (SIMD/CN1) 0.503x (49.7% faster)
Base64 encode ratio (SIMD/native) 0.090x (91.0% faster)
Base64 decode ratio (SIMD/native) 0.209x (79.1% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 8.000 ms
Image createMask (SIMD on) 2.000 ms
Image createMask ratio (SIMD on/off) 0.250x (75.0% faster)
Image applyMask (SIMD off) 53.000 ms
Image applyMask (SIMD on) 56.000 ms
Image applyMask ratio (SIMD on/off) 1.057x (5.7% slower)
Image modifyAlpha (SIMD off) 64.000 ms
Image modifyAlpha (SIMD on) 43.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.672x (32.8% faster)
Image modifyAlpha removeColor (SIMD off) 53.000 ms
Image modifyAlpha removeColor (SIMD on) 69.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 1.302x (30.2% slower)

@shai-almog

shai-almog commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 148 screenshots: 148 matched.
✅ Native Mac screenshot tests passed.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 322 seconds

Detailed Performance Metrics

Metric Duration
SIMD kernel backend SSE2 (x64) / NEON (arm64) native kernels
SIMD int-add (64K x300) java 70ms / native 7ms = 10.0x speedup
SIMD float-mul (64K x300) java 51ms / native 3ms = 17.0x speedup
SIMD kernel correctness PASS (native result == scalar reference)
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 SIMD byte path active (NEON-accelerated)
Base64 CN1 encode 170.000 ms
Base64 CN1 decode 131.000 ms
Base64 native encode 728.000 ms
Base64 encode ratio (CN1/native) 0.234x (76.6% faster)
Base64 native decode 332.000 ms
Base64 decode ratio (CN1/native) 0.395x (60.5% faster)
Base64 SIMD encode 62.000 ms
Base64 encode ratio (SIMD/CN1) 0.365x (63.5% faster)
Base64 SIMD decode 62.000 ms
Base64 decode ratio (SIMD/CN1) 0.473x (52.7% faster)
Base64 encode ratio (SIMD/native) 0.085x (91.5% faster)
Base64 decode ratio (SIMD/native) 0.187x (81.3% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 9.000 ms
Image createMask (SIMD on) 4.000 ms
Image createMask ratio (SIMD on/off) 0.444x (55.6% faster)
Image applyMask (SIMD off) 75.000 ms
Image applyMask (SIMD on) 65.000 ms
Image applyMask ratio (SIMD on/off) 0.867x (13.3% faster)
Image modifyAlpha (SIMD off) 85.000 ms
Image modifyAlpha (SIMD on) 75.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.882x (11.8% faster)
Image modifyAlpha removeColor (SIMD off) 54.000 ms
Image modifyAlpha removeColor (SIMD on) 38.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.704x (29.6% faster)

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f730882180

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread Ports/iOSPort/src/com/codename1/impl/ios/IOSContinuityCallbacks.java Outdated
Comment thread CodenameOne/src/com/codename1/continuity/AppState.java

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 33e4b0d530

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread CodenameOne/src/com/codename1/continuity/Continuity.java Outdated
Comment thread CodenameOne/src/com/codename1/continuity/Continuity.java Outdated
Comment thread CodenameOne/src/com/codename1/continuity/StateCodec.java Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: dca8d2d773

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread CodenameOne/src/com/codename1/continuity/Continuity.java Outdated
Comment thread CodenameOne/src/com/codename1/continuity/Continuity.java Outdated
Comment thread CodenameOne/src/com/codename1/continuity/Continuity.java
@shai-almog

shai-almog commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 149 screenshots: 149 matched.
✅ Native iOS Metal screenshot tests passed.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 1728 seconds

Build and Run Timing

Metric Duration
Simulator Boot 65000 ms
Simulator Boot (Run) 0 ms
App Install 16000 ms
App Launch 1000 ms
Test Execution 519000 ms

Detailed Performance Metrics

Metric Duration
SIMD kernel backend SSE2 (x64) / NEON (arm64) native kernels
SIMD int-add (64K x300) java 95ms / native 4ms = 23.7x speedup
SIMD float-mul (64K x300) java 89ms / native 7ms = 12.7x speedup
SIMD kernel correctness PASS (native result == scalar reference)
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 SIMD byte path active (NEON-accelerated)
Base64 CN1 encode 550.000 ms
Base64 CN1 decode 467.000 ms
Base64 native encode 2255.000 ms
Base64 encode ratio (CN1/native) 0.244x (75.6% faster)
Base64 native decode 7505.000 ms
Base64 decode ratio (CN1/native) 0.062x (93.8% faster)
Base64 SIMD encode 86.000 ms
Base64 encode ratio (SIMD/CN1) 0.156x (84.4% faster)
Base64 SIMD decode 52.000 ms
Base64 decode ratio (SIMD/CN1) 0.111x (88.9% faster)
Base64 encode ratio (SIMD/native) 0.038x (96.2% faster)
Base64 decode ratio (SIMD/native) 0.007x (99.3% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 10.000 ms
Image createMask (SIMD on) 4.000 ms
Image createMask ratio (SIMD on/off) 0.400x (60.0% faster)
Image applyMask (SIMD off) 165.000 ms
Image applyMask (SIMD on) 60.000 ms
Image applyMask ratio (SIMD on/off) 0.364x (63.6% faster)
Image modifyAlpha (SIMD off) 223.000 ms
Image modifyAlpha (SIMD on) 154.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.691x (30.9% faster)
Image modifyAlpha removeColor (SIMD off) 120.000 ms
Image modifyAlpha removeColor (SIMD on) 221.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 1.842x (84.2% slower)

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 217be7b114

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread CodenameOne/src/com/codename1/continuity/Continuity.java Outdated
…ync opt-in

routeStackChanged() returns early while a restore is being applied, and it has
to: without that the rebuild checkpoints and republishes the state it is
applying, and the two devices bounce it back and forth. But the restored form's
show callback is application code and may navigate -- a screen that redirects to
a newer one, an expired detail page sending the user to a list. Both
notifications for that navigation land inside the window and are dropped, so the
checkpoint recorded the routes that ARRIVED instead of the ones the user is on,
and a process death before the next one restored the screen the application had
redirected away from.

The reconciliation goes AFTER commit(), and the ordering is the whole of it.
commit() clears the pending flag as part of settling the arrival, so asking
before it set a flag commit then wiped and the scheduled flush found nothing
owed -- the fix looked right and did nothing, which the test caught. It is also
after the lifecycle branch, because a callback that ends the session leaves the
stack different from what was restored too, and checkpointing there writes for a
session that has just ended -- an existing test caught that one.

Separately, ios.continuity.sync=true is a DECLARATION and the build ignored it.
The hint documents itself as "set true to say so explicitly", and the signing
preflight already reads it that way -- it is how a project says it wants the
store without that check having to read bytecode. The builder used it only as a
veto, so a project that says so and whose usage the scan cannot see got neither
the entitlement nor the define, while the preflight warned about a profile for a
capability the build was never going to ask for. Both flags now, for the reason
the scan's own comment gives: an entitlement without the define is a SyncedStore
that reports itself unsupported on the device.

Only an explicit true does it. Unset still means "the bytecode decides", which is
what keeps an app that merely hands work to a nearby device from being given an
iCloud entitlement its App ID may not carry.

That half has no unit-test seam: the flag resolution lives inside build(), and
the plist tests beside it drive static helpers rather than the build flow. I
verified the placement instead -- both consumers, the entitlement block and
injectToPlist(), run later in the same method -- and the plugin's 1938 tests
still pass.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d667acb232

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread CodenameOne/src/com/codename1/continuity/Continuity.java
…y enable()

The door my own parking change opened, and the symmetry I missed when I closed
the same one for clear().

Callback.decide() parks an arrival that reaches the seam before the application
has chosen -- a synced-store listener installs that seam without enabling
continuity -- so by the time a logged-out app says "off" there can be a copy here
as well as at the port. disable()'s early return drained only the port's, and
enable() drains this slot on purpose, so the login restored a payload and routes
that arrived before the application said it wanted none. disable() documents the
opposite.

The full path below already clears it as part of ending the session; the early
return leaves before reaching that, which is the whole of the difference between
the two.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1f1aaf2ca3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread CodenameOne/src/com/codename1/continuity/Continuity.java Outdated
The previous commit put `parked = null` inside `if (!enabled)`, which is
check-a-static-then-assign-a-static and trips the forbidden PMD rule
NonThreadSafeSingleton. Both paths want it -- the full one clears the slot a few
lines further down anyway -- so it is hoisted above the split rather than
suppressed: one statement, said once, and the shape the rule objects to is gone.

Recording the process failure rather than only the fix: I ran the quality gate
and the commit in one chained command, so the push went out while the gate was
reporting a violation. The gate's exit code has to be read before the commit,
not beside it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8b44659b47

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

/// Hands an arrival to the framework, or holds it. Called on whatever thread the activity
/// arrived on; the framework marshals what it needs to.
private static boolean deliverToFramework(String activityType, String userInfoJson) {
ContinuityCallback c = callback;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Safely publish the installed iOS callback

When continuity is already enabled and iOS invokes nativeContinuation() on its platform thread, this unsynchronized read has no happens-before relationship with the EDT write in setCallback(), so it may still observe null. The arrival is then reported unclaimed and placed in pendingType/pendingJson, but no later callback installation is guaranteed to re-offer it, leaving a valid Handoff ignored indefinitely; publish the callback across threads or synchronously obtain it through EDT coordination.

Useful? React with 👍 / 👎.

ContinuityCallback lets a port call from any thread and says nothing about the
map outliving the call, so a port that recycles one buffer per arrival -- or
clears it once the call returns -- is within its rights. The off-EDT branch
queued only the reference and had ALREADY told that port the activity was
claimed, so the decision read whatever the bridge had put there since: a
different state, or none at all.

Read into an AppState before returning instead. fromMap() detaches it completely,
which is why no copy helper is needed here -- setPayload deep-copies, the routes
are rebuilt into a new list, and everything else a payload may hold is immutable
-- so what is queued is the framework's own object.

The claim gets honest with it, which is the part worth having: a document that
yields no state is now declined rather than claimed, because nothing was taken.

The test drives a bridge that empties and refills its map the instant the call
returns, and checks the payload that reaches the provider is the one that was
handed over. Without the fix nothing is delivered at all.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 285561b401

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread CodenameOne/src/com/codename1/router/Navigation.java Outdated
I gated the display half of this rollback last round and left the stack half
unconditional, which made the two disagree. A show callback that navigates
somewhere of its own and then throws -- or navigates and has a later listener
throw -- has already changed both, so erasing the stack while leaving that
screen up describes a place the user is not: back() then works on a history that
does not include what is in front of them.

Same rule as the ordinary navigations already use, and for the same reason:
whatever ran later and changed the stack meant to, and it wins.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a3878e3654

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread CodenameOne/src/com/codename1/continuity/Continuity.java
A state carrying a good payload and nothing storable beside it takes the
payload-only return, and that return reached commit() before the filtered set
was applied. persist() then threw on the original oversized route every time, so
the arrival stayed parked, was re-applied on every retry, and held every relay
publication behind it -- after the provider had already taken the payload.

This is the second time this one reconciliation was applied to one path and not
the other, so it stops being a statement placed near a path and becomes the
statement immediately after the filter it belongs to. Every exit below now
carries it, including ones nobody has thought of yet.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a0c90120fa

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread CodenameOne/src/com/codename1/continuity/Continuity.java Outdated
The slot holds one arrival and that is right: getRestorableState() answers with a
state, and an application that has not dealt with the last one does not want a
queue growing behind it. Replacing it is right too when the two come from the
SAME device -- that is supersession, and the newer sequence is the one worth
showing.

Two different devices are not that. With automatic restoration off, both can be
dispatched before the application calls restore(), and the second simply
overwrote the first. That would be survivable if the first could come back, and
it could not: its (origin, sequence) went into the in-memory map at admission, so
a redelivery in the same run was refused as already seen. Recorded as handled,
then dropped, and gone for the rest of the process.

So the mark goes with it. Only the in-memory one -- durableSeen is written when a
state COMPLETES and this one never did, so nothing durable claims it -- and only
while it still names the dropped state, so a newer mark for that origin is left
alone.

Kept as one slot rather than a queue per origin, which is where the report left
the choice open: the single slot is the documented shape of getRestorableState(),
and the defect was that dropping was irreversible, not that dropping happens.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b07b136a2b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread CodenameOne/src/com/codename1/continuity/Continuity.java Outdated
Last commit made a replaced offer recoverable and applied that at two of the
FIVE places a state is put on offer. A listener that returns false for device A
and then for device B before A is resolved goes through a third, so B replaced A
with A's mark still recorded and A could never be offered again in that run --
the same defect, one call site over.

All five go through placeOnOffer() now: the cold-launch hold before the event
thread exists, the wait for a first window, the listener's hold, the pre-enable
hold, and the deferred-restore hold. Each is a place where a second arrival can
find one already waiting, which is why fixing them one at a time kept missing
one.

The test seam goes through it too, so a test that parks twice exercises what the
framework actually does rather than a shortcut past it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4a3177ddc2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread CodenameOne/src/com/codename1/continuity/Continuity.java
dispatch() already keeps an ARRIVAL whose restore failed, for the reason its own
comment gives: a provider that throws is usually transient, so the state is worth
holding for a retry. The application-driven restore() did not do the same for a
state that came from STORAGE.

So a cold start whose provider threw -- a dependency not up yet, which is the
transient the whole failure branch exists for -- left the on-device checkpoint as
the only copy, and the next navigation checkpointed the fallback screen over it.
The draft the user was promised is gone at exactly the moment "restore, or else
begin" is meant to protect it.

A no-op when the state came from the slot, because placeOnOffer() returns
immediately when asked to replace something with itself, so the arrival path is
unchanged.

It does hold relay publication until the application resolves the state, by
retrying or acknowledging. That is the same hold a failed arrival already takes
and for the same reason: what is on the relay is worth more than what this device
would write over it while it cannot even load its own payload. Saying so here
because it is a real cost, not a free win.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a25f362063

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread CodenameOne/src/com/codename1/continuity/Continuity.java
Comment thread CodenameOne/src/com/codename1/router/Navigation.java
…ctory redirect win

dispatch() and getRestorableState() both check maxAge and neither is the last
word. The documented flow is that a listener returns false, puts a prompt in
front of the user, and calls restore(state) when they accept -- and the deciding
is exactly the time that passes. A state fresh when it was offered can be stale
when it is taken, and an expired checkout or booking hold is precisely what
maxAge exists to refuse. It is discarded the way getRestorableState() discards
one, rather than left on offer to be handed back again: the slot is released and
the publisher let go, because the hold existed for a state that will never be
applied.

Separately, a route FACTORY may redirect -- an expired detail page sending the
user to a list -- and it does so before restoreStack() has installed anything, so
the rebuild replaced both its stack entry and its screen. Its choice wins now,
the same rule the rollback and the ordinary navigations already use. Returning
false means Continuity treats the restore as showing nothing, and the
reconciliation added earlier checkpoints the stack the factory left behind, so
the two compose rather than needing a second mechanism.

The factory test needed a second look: the first version had the factory answer
null, which the empty-rebuild check already covers, so it passed with the new
guard removed. It answers with a form now, which is what makes the rebuild
non-empty and the guard the thing under test.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 65d0414c4d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread CodenameOne/src/com/codename1/router/Navigation.java Outdated
Comment thread CodenameOne/src/com/codename1/router/Navigation.java
Both of these are the cost of the factory-redirect guard I added an hour ago,
and both are things that guard should have done from the start.

The stack comparison sat after the whole loop, so every later factory still
constructed its screen and touched whatever the application keeps behind it --
an unavailable parent redirecting to a safe list while its child factories go on
reading the record that is unavailable -- and all of it was then discarded in
favour of the redirect. It is asked per iteration now, and once more after the
loop because the last factory has no next iteration to be stopped by. That is
the same pairing the session check beside it already uses, which is what it
should have been copied from.

And restoreStack() returning false read as "nothing happened", so a route-only
arrival took the failure branch: parked, holding relay publication, and offered
again after every launch to redirect again. The application DID handle it, by
going somewhere else. Continuity compares the live stack with what it was before
the rebuild, so a redirect from a factory OR from a show callback settles the
arrival and checkpoints where the user actually ended up.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: dd5abcbdda

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread CodenameOne/src/com/codename1/continuity/Continuity.java

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: dd5abcbdda

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread CodenameOne/src/com/codename1/continuity/Continuity.java Outdated
Comment thread CodenameOne/src/com/codename1/continuity/Continuity.java
…nstalled

Replacing a same-origin offer is supersession, and supersession has a direction.
The comment there has always said the newer sequence is the one worth showing
and nothing checked: arrivals do not land in the order they were sent, so a
delayed sequence 10 landing after 11 replaced it and moved the user backward.
admit() has this check; the pre-enable path does not go through admit(), so the
states a synced-store listener's seam collects before enable() arrive here
unordered -- and both copies have already been claimed from the port, so the
newer one is simply gone.

And the lifecycle branch emptied the stack unconditionally. A callback that ends
the session and then goes somewhere -- clear() and then navigate("/login"), the
ordinary shape of a logout discovered mid-restore -- has already replaced it, so
emptying removed the login entry too: the display guard kept the login FORM, and
getCurrent() showed it while Navigation.getCurrent() was null and back() had
nothing. disable() during a restore did worse, destroying the pre-restore history
for something that is not a logout at all. Same rule as the two rollbacks in
Navigation: undo what this restore installed, leave what application code chose.

The tests in this class also clean the navigation stack now. Nothing resets
Navigation between them, so a test that leaves entries behind breaks the NEXT
test's fixture rather than its own assertions -- which is exactly what happened
when the unconditional clear stopped covering for it, and the full-suite run
caught it where the single-test runs could not.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9b124a514d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread CodenameOne/src/com/codename1/continuity/Continuity.java Outdated
shai-almog and others added 2 commits September 5, 2026 16:49
The offer slot holds one arrival, which is the right shape for
getRestorableState() -- the application is asked about one thing at a time.
It is the wrong shape for HOLDING, and those two jobs shared one field.
Two devices can each offer work while automatic restoration is off, or
while a listener defers both, and the second arrival simply overwrote the
first.

The previous fix forgot the displaced state's admission mark so that a
redelivery could bring it back. That bet on a delivery which is not coming.
The off-EDT callback claims what it queues -- it has to, the decision is
made later on the event thread and the port is owed an answer now -- so a
conforming bridge is entitled to drop its copy the moment it hands over.
Nothing would ever deliver that state again.

So displacement shelves rather than drops, one entry per origin, and
getRestorableState() promotes the newest shelved arrival once the slot
empties. The public shape is unchanged: still one state at a time, still
the newest first.

Every way an arrival ends had to reach the shelf as well as the slot, which
is where the increments in this area have kept going wrong -- a fix applied
to one exit of several. All of them, enumerated: a restore that commits, an
acknowledge(), a tombstone from that origin, expiry, clear(), disable() on
both its paths, and reset(). Relay publication is held for a shelved
arrival too, and more obviously than for a parked one: the port has already
been told the framework took it, so this process holds the only copy there
is.

Bounded at eight, oldest evicted. The shelf holds whole states, payloads
included, and the device ids that key it come off the wire -- an unbounded
one lets whatever is on the other end of the relay decide how much memory
this process uses.

The shelf takes only states that carry an origin. Keying an unidentified
one under null looked harmless and was not: with two of them in a row, the
same call that shelved the first looked a null origin straight back up,
pulled it out again, and -- its sequence being the higher of the two --
handed it the slot and dropped the arrival that had just displaced it. The
loss this mechanism exists to prevent, produced by the mechanism. Nothing
the shelf does works without an origin, and a continuation always carries
one; what arrives here without one is a state the application built and
handed to restore(), which it still holds a reference to.

Seven tests, each probed by mutating the guard it covers and confirming it
fails: the two rewritten cross-origin tests now assert the state comes back
with NOTHING redelivering it, and the new ones cover the tombstone, the
publication hold, expiry with the application never asking (the case the
slot's own expiry cannot reach, since asking is what discards a parked
state), clear(), the bound, and the unidentified-state swap above.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… other port has

Unrelated to continuity, and carried here because it is what has been
keeping this branch's javascript-screenshots leg red. It also fails on
branches with no continuity code at all, so it is not this work's doing.

The test encodes six frames and decodes them back, comparing whatever the
platform codec returns -- lossy, and not bit-reproducible. Its own javadoc
says each baseline ships a generous .tolerance file, and every comparing
port does, at identical values. scripts/javascript/screenshots/ was the one
that did not, so readTolerance fell back to the harness defaults in
ProcessScreenshots -- maxChannelDelta=4, maxMismatchPercent=0.30 -- and
ordinary decode noise failed the build.

Measured on the failure rather than assumed: the worst single-channel delta
anywhere was 20/255, 2.611% of pixels exceeded delta 4, and 0.000% exceeded
delta 72. The regressions this test exists to catch -- frames blank,
reordered, wrong colour -- move whole blocks across most of the channel
range, so this does not stop catching them.

The baseline PNG is untouched, so this is not a reseed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3de7bc2704

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +2863 to +2868
Display.getInstance().callSeriallyAndWait(new Runnable() {
@Override
public void run() {
present[0] = Display.getInstance().getCurrent() != null;
}
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Bound the EDT wait by the cold-launch deadline

When the EDT remains busy for longer than 15 seconds during a cold launch, this non-timeout callSeriallyAndWait() blocks the waiter indefinitely, so the loop cannot recheck WINDOW_WAIT_MILLIS. If the EDT recovers minutes later, windowWaitFinished() can still dispatch the old continuation and unexpectedly replace whatever the user is then doing, despite the documented bounded window; use the timed overload with the remaining deadline.

Useful? React with 👍 / 👎.

Comment on lines +1626 to +1630
discardHeldArrival = true;
try {
installCallback(true);
} finally {
discardHeldArrival = false;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Bind asynchronously re-offered arrivals to the cleared session

When a custom bridge re-offers its held continuation asynchronously from setCallback()—permitted because ContinuityBridge allows callbacks from any thread and does not require inline delivery—this finally clears discardHeldArrival before that callback runs. Because clear() leaves enabled unchanged, the delayed callback captures the new lifecycle and accepts the pre-clear state, or parks it for a later enable() when clearing occurred before enablement, allowing prior-account work to survive logout. Fresh evidence beyond the earlier clear-before-enable report is that the current fix relies on the re-offer completing synchronously even though the bridge contract does not impose that ordering.

Useful? React with 👍 / 👎.

@shai-almog

shai-almog commented Sep 5, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 217 screenshots: 217 matched.
✅ Native Apple Watch (watchOS, Core Graphics) screenshot tests passed.

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