Skip to content

Developer guide: settle the seven Monetization sentences that promise code - #5810

Merged
shai-almog merged 17 commits into
masterfrom
dg-monetization
Sep 14, 2026
Merged

Developer guide: settle the seven Monetization sentences that promise code#5810
shai-almog merged 17 commits into
masterfrom
dg-monetization

Conversation

@shai-almog

Copy link
Copy Markdown
Collaborator

Monetization had the largest cluster of missing code blocks in the guide — seven sentences ending in a colon with nothing after them, left from the snippet extraction in bbdc6058f0.

They are two different problems and are fixed two different ways.

Restored as compiled snippets (2)

Ordinary Codename One code, recovered from bbdc6058f0~1:

  • the button that calls synchronizeReceipts
  • the main-form label that reads getExpiryDate after a sync

Both now live in the demos module and compile with everything else, so they cannot silently rot again.

Pointed at the source (5)

The rest describe server-side JAX-RS and JPA, or client code built on the RESTfulWebServiceClient cn1lib. None of it compiles in a Codename One module — which is why it was dropped, and why restoring it would mean either standing up a second build or writing an inline block that validate-guide-snippets.py rejects.

Those sentences now point at the two demo projects the chapter already links, which is where that code actually lives and stays current. A promise of a listing that cannot be kept is worse than a pointer to the real thing.

The NetBeans web service wizard reference goes with them: it generated the controller years ago, it is not how anyone would produce one today, and the sentence carried it purely as provenance.

Result

check-missing-code-blocks ratchet drops 34 → 27, and the gate confirmed all seven were settled before the baseline was rewritten.

  • structure (122 documents), xrefs (1691 anchors), links, unused images, alt text — clean
  • validate-guide-snippets.py — 1109 include-backed blocks, up from 1107, and the two new snippets compile
  • asciidoctor --failure-level WARN and asciidoctor-pdf — clean
  • Vale 0 alerts; LanguageTool status: ok, total: 0
  • capitalization, control characters, copyright headers — clean; both snippets pure ASCII

… code

The chapter had the largest cluster of holes in the guide: seven sentences
ending in a colon with nothing after them, left over from the snippet
extraction. Two kinds, handled differently, because they are different problems.

Two are ordinary Codename One code and are restored as compiled snippets: the
button that calls synchronizeReceipts, and the main-form label that reads
getExpiryDate after a sync. Both recovered from bbdc605~1 and now compile
with the rest, so they cannot rot again.

Five describe server-side JAX-RS and JPA, or client code built on the
RESTfulWebServiceClient cn1lib. None of it compiles in a Codename One module,
which is why it was dropped and why restoring it would mean either a second
build or an inline block the snippet validator rejects. Those sentences now
point at the two demo projects the chapter already links, which is where the
code actually lives and stays current.

The NetBeans web service wizard goes with them. It generated the controller
years ago, it is not how anyone would produce one now, and the sentence was
carrying it purely as provenance.

Ratchet drops from 34 to 27.

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

chatgpt-codex-connector Bot commented Sep 13, 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-13T18:36:44.921733Z 935a3df 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: 5a962a2041

ℹ️ 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 docs/developer-guide/Monetization.asciidoc
synchronizeReceipts reports true only when every pending purchase reached
the receipt store AND the receipts came back, so the expiry-label listing
was presenting a stale cached status as a fresh answer whenever the network
leg failed. It now branches on the flag and says which it is showing; the
reason is in a comment beside the branch, because the trap is in the
callback's contract rather than in this code.

Both listings also built a component and dropped it. A reader copying the
manual-sync listing got a Button that is never added to anything and a
listener that can never run. Both now add what they build to the form.

And the CN1-IAP-Validator section still opened its follow-up with "As you
can see from this snippet" after the snippet became a pointer to the server
project. It now names the project.

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: 1824002e60

ℹ️ 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".

The prose says the main form shows the current expiry date and the button
is there for a user who thinks that value is out of date, but the listing
set the label only from inside the listener, so a form nobody pressed sat
on "Loading rental details..." forever. The receipts already on the device
answer the question with no round trip, so the label is now filled in as
the form is built and the sync path reuses the same method.

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: 499df394aa

ℹ️ 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".

… had

The failure branch replaced the expiry label with an error string that
said it was showing the last known status, which is the one thing it was
not doing. Nothing was reloaded on that path, so there is nothing new to
put in the label: the error goes to a ToastBar and the label keeps the
answer the receipts already gave.

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: f8c8ce092f

ℹ️ 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".

The chapter synchronizes receipts in two places -- once at the end of
start(), once behind a manual button -- and only the button's path was
touching the expiry label. Stale receipts at launch therefore stayed on
screen until the user pressed a button they had no reason to press,
which is exactly the case the automatic sync exists to cover.

The label is now a field rather than a local, and both callbacks call the
same showRentalStatus(). The start() listing's callback stops being a
comment and does the thing the comment described.

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

Copy link
Copy Markdown
Contributor

Cloudflare Preview

@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: 5cce9e5742

ℹ️ 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".

The chapter shows the manual button, then shows it again as part of the
expiry-label listing, so a reader following it in order builds two of
them and only the second one refreshes anything.

There is only one button in the app being described, so there is now only
one in the listings. The button listing owns it and calls the same
showRentalStatus() that start() calls; the expiry listing is reduced to
what it is actually introducing -- the label, the field it lives in, and
the method that paints it from the receipts already on the device.

The sentence above it said the reader would add a button there, which is
why the second one existed at all. It now says what the listing does.

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: bb209355c2

ℹ️ 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".

hi is a local of start() in the hello-world app the chapter builds, and
the Form field these snippet wrappers carry sits outside the AsciiDoc tag,
so the published listings referred to something a reader copying them
cannot see and could not compile. Both helpers now take the Form.

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: 99bc5b2c45

ℹ️ 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".

Following the listings in order produced a form with neither the expiry
label nor the sync button on it, because the only listing that runs at
startup did the synchronization and nothing else. start() now builds the
form and calls both helpers, so the three listings assemble into the app
the chapter describes.

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: c586ed88ad

ℹ️ 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".

@github-actions

github-actions Bot commented Sep 13, 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)

Every listing from the non-renewable-subscription section onward calls
iap.isSubscribed(PRODUCTS) or iap.getExpiryDate(PRODUCTS), and no published
block ever declared either name -- the snippet wrappers carry them outside
the tag, so the code in the book referred to something a reader could not
see. The prose introduces PRODUCTS in the same breath ("the example uses an
array"), and the paragraph that follows it opens with "Notice that you
create two separate SKUs", which is a sentence about a listing that was no
longer there.

The three declarations now appear where the chapter introduces them, once,
ahead of every listing that uses them.

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: ca3a585aaf

ℹ️ 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".

Codename One calls start() again when the app is resumed, and the listing
built a fresh Form every time and handed it components the first form still
owns -- insertComponentAtImpl rejects a component that already has a parent,
so the app the chapter describes throws on resume. The earlier start()
listing in this same chapter already carries the current-form guard; this
one now does too.

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: 7060a2daa9

ℹ️ 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".

…aunch does

The guard I added last round returned before the synchronization, so a
resume showed the old form and never refreshed it -- and a resume is
exactly when a subscription bought, renewed or cancelled on another device
becomes visible. The sync now sits outside the branch: the launch builds
the form, the resume shows the one that survived, and both fall through to
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: a4d7c32289

ℹ️ 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".

itemPurchased already reloads the receipts and then only showed a toast, so
the form behind it kept saying the user has no subscription right after they
bought one -- until a manual sync or a resume. It now calls the same
showRentalStatus() the other two paths call, and revalidates.

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: 0310641f7e

ℹ️ 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".

Receipts are cached on the Purchase instance -- the field is per-object and
loaded lazily -- and most ports hand back a fresh instance from every
getInAppPurchase() call. The purchase callback made its own, synchronized
that, and then repainted from the shared one, which had not been touched:
the label kept the answer it had before the purchase, which is exactly the
bug the repaint was added to fix.

It now uses the shared instance the rest of the chapter declares.

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: 0940e4429e

ℹ️ 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".

Both listeners held their own getInAppPurchase(), so after a purchase
synchronized the shared instance the next click still described the state
from before it -- "you're already renting the world until <old date>", or
no subscription at all. They use the shared field now, and their purchase()
calls go through it as well rather than making yet another instance.

The one-time-purchase listings earlier in the chapter are left alone on
purpose: wasPurchased() is implemented per port and does not read the
instance receipt cache, so nothing there goes stale.

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: fb043b0f4a

ℹ️ 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".

Two rounds of this thread moved toward sharing one Purchase across the
chapter. Reading the class settles it the other way.

synchronizeReceipts coalesces on a static syncInProgress, so a second call
while the port's own synchronization is running registers its callback and
returns without loading anything. The receipts it waits for land in the
instance the port created, via setReceipts, which writes the instance field
AND persists to storage. A held instance never sees them; its cache is
loaded once, lazily, and nothing invalidates it.

The shared state is therefore the persisted receipts, not a shared object.
Every use site now takes a fresh getInAppPurchase(), whose cache loads from
storage on first read -- after the synchronization has written there. That
is a storage read rather than a network call, and it is what the ports
themselves do.

The declarations listing drops the field and says why, and the purchase
callback notes that nothing reads receipts off its instance until after the
synchronous sync, which is what makes the order work.

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: d51458ee10

ℹ️ 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".

iOS adds its StoreKit transaction observer while the view controller is
being set up, so an unfinished transaction is re-delivered to
itemPurchased() before start() has built anything. The listing then
dereferenced a form that did not exist yet.

The label is a field and is safe to set, so the status still gets written;
only the revalidate is guarded, and start() paints from the same method
when it does run.

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: b56b53309f

ℹ️ 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".

synchronizeReceipts coalesces on a static syncInProgress, so a purchase
completing mid-fetch queues its receipt through postReceipt and cannot
start a synchronization of its own. The fetch already in flight was
requested before that receipt existed, and onLoadReceiptsComplete reported
its success to every waiting caller -- so the caller got a snapshot that
predates the purchase and the receipt stayed pending until something
synchronized again. On a subscription app that is a purchase the user made
and the app does not show.

onLoadReceiptsComplete now re-runs when the pending queue is non-empty,
the same way onSubmitReceiptComplete already continues draining. The
registered callbacks are untouched and fire from that later pass, so the
existing "callback fires exactly once" guarantee holds.

The receiptStore null check is load-bearing rather than defensive: with no
store, synchronizeReceipts skips the submit branch and comes straight back
here with the queue still non-empty. There is already a test in this suite
for the sibling infinite-recursion case, which is what made the hazard
obvious.

Found while checking a developer-guide listing that repaints a subscription
label from this callback. Verified by reverting the fix: the new test fails
with "expected: <1> but was: <0>" -- the receipt never submitted -- and
passes with it, 18/18 in the class either way otherwise.

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

shai-almog commented Sep 13, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 151 screenshots: 151 matched.

Native Android coverage

  • 📊 Line coverage: 9.24% (9188/99417 lines covered) [HTML preview] (artifact android-coverage-report, jacocoAndroidReport/html/index.html)
    • Other counters: instruction 9.00% (47232/524920), branch 3.56% (1772/49739), complexity 3.53% (1873/53026), method 5.44% (1516/27888), class 10.92% (408/3736)
    • 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.24% (9188/99417 lines covered) [HTML preview] (artifact android-coverage-report, jacocoAndroidReport/html/index.html)
    • Other counters: instruction 9.00% (47232/524920), branch 3.56% (1772/49739), complexity 3.53% (1873/53026), method 5.44% (1516/27888), class 10.92% (408/3736)
    • 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 231ms / native 112ms = 2.0x speedup
SIMD float-mul (64K x300) java 153ms / native 84ms = 1.8x 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 144.000 ms
Base64 CN1 decode 116.000 ms
Base64 native encode 598.000 ms
Base64 encode ratio (CN1/native) 0.241x (75.9% faster)
Base64 native decode 448.000 ms
Base64 decode ratio (CN1/native) 0.259x (74.1% faster)
Image encode benchmark status skipped (SIMD unsupported)

@github-actions

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.

@shai-almog

shai-almog commented Sep 13, 2026

Copy link
Copy Markdown
Collaborator Author

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

@shai-almog

shai-almog commented Sep 13, 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: 136 seconds

Detailed Performance Metrics

Metric Duration
SIMD kernel backend SSE2 (x64) / NEON (arm64) native kernels
SIMD int-add (64K x300) java 55ms / native 2ms = 27.5x speedup
SIMD float-mul (64K x300) java 55ms / native 3ms = 18.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 active (NEON-accelerated)
Base64 CN1 encode 162.000 ms
Base64 CN1 decode 96.000 ms
Image encode benchmark iterations 100
Image createMask (SIMD off) 5.000 ms
Image createMask (SIMD on) 2.000 ms
Image createMask ratio (SIMD on/off) 0.400x (60.0% faster)
Image applyMask (SIMD off) 32.000 ms
Image applyMask (SIMD on) 22.000 ms
Image applyMask ratio (SIMD on/off) 0.688x (31.3% faster)
Image modifyAlpha (SIMD off) 32.000 ms
Image modifyAlpha (SIMD on) 22.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.688x (31.3% faster)
Image modifyAlpha removeColor (SIMD off) 28.000 ms
Image modifyAlpha removeColor (SIMD on) 23.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.821x (17.9% faster)

@shai-almog

shai-almog commented Sep 13, 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: 252 seconds

Detailed Performance Metrics

Metric Duration
SIMD kernel backend SSE2 (x64) / NEON (arm64) native kernels
SIMD int-add (64K x300) java 60ms / native 7ms = 8.5x speedup
SIMD float-mul (64K x300) java 53ms / native 3ms = 17.6x 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 157.000 ms
Base64 CN1 decode 92.000 ms
Base64 native encode 645.000 ms
Base64 encode ratio (CN1/native) 0.243x (75.7% faster)
Base64 native decode 199.000 ms
Base64 decode ratio (CN1/native) 0.462x (53.8% faster)
Base64 SIMD encode 48.000 ms
Base64 encode ratio (SIMD/CN1) 0.306x (69.4% faster)
Base64 SIMD decode 44.000 ms
Base64 decode ratio (SIMD/CN1) 0.478x (52.2% faster)
Base64 encode ratio (SIMD/native) 0.074x (92.6% faster)
Base64 decode ratio (SIMD/native) 0.221x (77.9% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 7.000 ms
Image createMask (SIMD on) 1.000 ms
Image createMask ratio (SIMD on/off) 0.143x (85.7% faster)
Image applyMask (SIMD off) 40.000 ms
Image applyMask (SIMD on) 23.000 ms
Image applyMask ratio (SIMD on/off) 0.575x (42.5% faster)
Image modifyAlpha (SIMD off) 28.000 ms
Image modifyAlpha (SIMD on) 21.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.750x (25.0% faster)
Image modifyAlpha removeColor (SIMD off) 26.000 ms
Image modifyAlpha removeColor (SIMD on) 21.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.808x (19.2% faster)

@shai-almog

shai-almog commented Sep 14, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 144 screenshots: 144 matched.
✅ Native Apple TV (tvOS, Metal) screenshot tests passed.

@shai-almog

shai-almog commented Sep 14, 2026

Copy link
Copy Markdown
Collaborator Author

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

@shai-almog
shai-almog merged commit 0527b5e into master Sep 14, 2026
40 of 42 checks passed
@shai-almog
shai-almog deleted the dg-monetization branch September 14, 2026 01:42
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.

1 participant