Skip to content

DeviceIntegrity: RASP, Play Integrity / App Attest, accessibility-service guard#5277

Merged
shai-almog merged 6 commits into
masterfrom
feature/device-integrity-rasp
Jun 25, 2026
Merged

DeviceIntegrity: RASP, Play Integrity / App Attest, accessibility-service guard#5277
shai-almog merged 6 commits into
masterfrom
feature/device-integrity-rasp

Conversation

@shai-almog

Copy link
Copy Markdown
Collaborator

Summary

Adds a portable device-integrity / runtime self-protection (RASP) API plus build hints, implemented in the core framework — no cn1lib, no customer native interfaces. Built for high-security apps (banking/payments) that need to detect and react to a hostile runtime.

New facade com.codename1.security.DeviceIntegrity:

Need Build hint (zero-code) Runtime API
Play Integrity launch gate android.playIntegrity (+.verifyUrl) requestIntegrityToken(nonce)
iOS App Attest ios.appAttest (+.environment) same
RASP root/jailbreak/Frida existing android.rootCheck / android.fridaDetection / ios.detectJailbreak isDeviceCompromised() / getCompromiseReasons()
Accessibility-abuse guard android.accessibilityGuard (+.allow, +.mode) getEnabledAccessibilityServices(), hasUntrustedAccessibilityService(...), setSecureScreen(bool)

Design

  • Portable API surfaced through Display, defaulting to unsupported in CodenameOneImplementation; overridden in the Android and iOS ports (mirrors the existing isJailbrokenDevice() chain).
  • Android: Play Integrity + RootBeer invoked via reflection so the port jar stays dependency-free (the SDK is only present when the build hint bundles it).
  • iOS: App Attest via DCAppAttestService, native code gated behind CN1_USE_APP_ATTEST (stub #else so non-attest builds neither import nor link DeviceCheck.framework); async result returns via DCE-guarded static callbacks, the IOSBiometrics pattern.
  • Attestation tokens are opaque and must be verified server-side — the API delivers the signed token; the block/allow policy lives in the app's backend.

Scope

  • Core API + Android/iOS port impls
  • Build-hint wiring in the local maven-plugin builders (the cloud BuildDaemon has the matching change in a separate PR on that repo)
  • Developer-guide security chapter: new "Device integrity, RASP & attestation" section
  • DeviceIntegrityTest (6 tests) covering the accessibility allow-list evaluation

Verification

Core, local builders, Android port, and iOS-port Java all compile (JDK 8 core / JDK 17 Android); DeviceIntegrityTest passes (6/6).

🤖 Generated with Claude Code

… guard

Adds a portable device-integrity / runtime self-protection (RASP) API plus
build hints, implemented in the core framework (no cn1lib, no native
interfaces). Targets high-security apps that must react to a hostile runtime.

New core API com.codename1.security.DeviceIntegrity:
- requestIntegrityToken(nonce): server-verifiable attestation token (Google
  Play Integrity on Android, Apple App Attest on iOS) for gating sensitive
  actions such as transfers from a compromised device.
- isDeviceCompromised() / getCompromiseReasons(): non-exiting RASP report
  (root/jailbreak/Frida/emulator) for granular runtime decisions.
- getEnabledAccessibilityServices() / hasUntrustedAccessibilityService(...):
  detect malware abusing Android accessibility services.
- setSecureScreen(bool): Android FLAG_SECURE for sensitive screens.

Surfaced through Display, defaulting to "unsupported" in
CodenameOneImplementation; implemented in the Android port (Play Integrity /
RootBeer via reflection to keep the port dependency-free) and the iOS port
(App Attest via DeviceCheck, gated behind CN1_USE_APP_ATTEST).

Build-hint wiring (mirrored in the local maven-plugin builders; the cloud
BuildDaemon is updated separately): android.playIntegrity(+.verifyUrl),
ios.appAttest(+.environment), android.accessibilityGuard(+.allow,+.mode).

Docs: new "Device integrity, RASP & attestation" section in the developer
guide security chapter. Tests: DeviceIntegrityTest covers the accessibility
allow-list evaluation.

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

github-actions Bot commented Jun 24, 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)

@shai-almog

shai-almog commented Jun 24, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 136 screenshots: 136 matched.

Native Android coverage

  • 📊 Line coverage: 14.44% (8856/61335 lines covered) [HTML preview] (artifact android-coverage-report, jacocoAndroidReport/html/index.html)
    • Other counters: instruction 11.72% (43651/372561), branch 5.18% (1815/35055), complexity 6.18% (2076/33568), method 10.72% (1680/15677), class 17.51% (389/2221)
    • Lowest covered classes
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysKt – 0.00% (0/6327 lines covered)
      • kotlin.collections.unsigned.kotlin.collections.unsigned.UArraysKt___UArraysKt – 0.00% (0/2384 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.ClassReader – 0.00% (0/1519 lines covered)
      • kotlin.collections.kotlin.collections.CollectionsKt___CollectionsKt – 0.00% (0/1148 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.MethodWriter – 0.00% (0/923 lines covered)
      • kotlin.sequences.kotlin.sequences.SequencesKt___SequencesKt – 0.00% (0/730 lines covered)
      • kotlin.text.kotlin.text.StringsKt___StringsKt – 0.00% (0/623 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.Frame – 0.00% (0/564 lines covered)
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysJvmKt – 0.00% (0/495 lines covered)
      • kotlinx.coroutines.kotlinx.coroutines.JobSupport – 0.00% (0/423 lines covered)

✅ Native Android screenshot tests passed.

Native Android coverage

  • 📊 Line coverage: 14.44% (8856/61335 lines covered) [HTML preview] (artifact android-coverage-report, jacocoAndroidReport/html/index.html)
    • Other counters: instruction 11.72% (43651/372561), branch 5.18% (1815/35055), complexity 6.18% (2076/33568), method 10.72% (1680/15677), class 17.51% (389/2221)
    • Lowest covered classes
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysKt – 0.00% (0/6327 lines covered)
      • kotlin.collections.unsigned.kotlin.collections.unsigned.UArraysKt___UArraysKt – 0.00% (0/2384 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.ClassReader – 0.00% (0/1519 lines covered)
      • kotlin.collections.kotlin.collections.CollectionsKt___CollectionsKt – 0.00% (0/1148 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.MethodWriter – 0.00% (0/923 lines covered)
      • kotlin.sequences.kotlin.sequences.SequencesKt___SequencesKt – 0.00% (0/730 lines covered)
      • kotlin.text.kotlin.text.StringsKt___StringsKt – 0.00% (0/623 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.Frame – 0.00% (0/564 lines covered)
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysJvmKt – 0.00% (0/495 lines covered)
      • kotlinx.coroutines.kotlinx.coroutines.JobSupport – 0.00% (0/423 lines covered)

Benchmark Results

Detailed Performance Metrics

Metric Duration
SIMD kernel backend scalar fallback (no native SIMD)
SIMD int-add (64K x300) java 137ms / native 166ms = 0.8x speedup
SIMD float-mul (64K x300) java 172ms / native 99ms = 1.7x 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 277.000 ms
Base64 CN1 decode 194.000 ms
Base64 native encode 914.000 ms
Base64 encode ratio (CN1/native) 0.303x (69.7% faster)
Base64 native decode 828.000 ms
Base64 decode ratio (CN1/native) 0.234x (76.6% faster)
Image encode benchmark status skipped (SIMD unsupported)

@github-actions

Copy link
Copy Markdown
Contributor

Cloudflare Preview

@shai-almog

shai-almog commented Jun 24, 2026

Copy link
Copy Markdown
Collaborator Author

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

- IOSNative.m: include com_codename1_impl_ios_IOSDeviceIntegrity.h so the
  App Attest native callbacks are declared (fixes the undeclared-function
  error that broke all iOS/mac/packaging builds).
- DeviceIntegrity: make the class final and use foreach loops (PMD).
- security.asciidoc: satisfy the Vale Microsoft style (contractions,
  "for example" instead of "e.g.", drop the flagged adverb, backtick `su`).
- languagetool-accept.txt: accept the new security/RASP vocabulary
  (RASP, MTD, RootBeer, Magisk, Cydia, MobileSubstrate, FridaGadget,
  dylibs, Zimperium, Promon, DeviceCheck).

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

shai-almog commented Jun 24, 2026

Copy link
Copy Markdown
Collaborator Author

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

@shai-almog

shai-almog commented Jun 24, 2026

Copy link
Copy Markdown
Collaborator Author

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

Core src is checkstyle-gated (WhitespaceAfter); use 'if ('/'for (' to match
house style. Verified 0 violations locally with checkstyle 9.3 + the project
config.

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

shai-almog commented Jun 24, 2026

Copy link
Copy Markdown
Collaborator Author

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

Benchmark Results

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

Build and Run Timing

Metric Duration
Simulator Boot 76000 ms
Simulator Boot (Run) 2000 ms
App Install 22000 ms
App Launch 2000 ms
Test Execution 386000 ms

Detailed Performance Metrics

Metric Duration
SIMD kernel backend SSE2 (x64) / NEON (arm64) native kernels
SIMD int-add (64K x300) java 334ms / native 4ms = 83.5x speedup
SIMD float-mul (64K x300) java 82ms / native 4ms = 20.5x 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 785.000 ms
Base64 CN1 decode 373.000 ms
Base64 native encode 2232.000 ms
Base64 encode ratio (CN1/native) 0.352x (64.8% faster)
Base64 native decode 750.000 ms
Base64 decode ratio (CN1/native) 0.497x (50.3% faster)
Base64 SIMD encode 104.000 ms
Base64 encode ratio (SIMD/CN1) 0.132x (86.8% faster)
Base64 SIMD decode 67.000 ms
Base64 decode ratio (SIMD/CN1) 0.180x (82.0% faster)
Base64 encode ratio (SIMD/native) 0.047x (95.3% faster)
Base64 decode ratio (SIMD/native) 0.089x (91.1% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 40.000 ms
Image createMask (SIMD on) 7.000 ms
Image createMask ratio (SIMD on/off) 0.175x (82.5% faster)
Image applyMask (SIMD off) 90.000 ms
Image applyMask (SIMD on) 160.000 ms
Image applyMask ratio (SIMD on/off) 1.778x (77.8% slower)
Image modifyAlpha (SIMD off) 123.000 ms
Image modifyAlpha (SIMD on) 551.000 ms
Image modifyAlpha ratio (SIMD on/off) 4.480x (348.0% slower)
Image modifyAlpha removeColor (SIMD off) 366.000 ms
Image modifyAlpha removeColor (SIMD on) 263.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.719x (28.1% faster)

8.0 is not a released tag (the line is at 8.0.83) and the markdown
'#### Since' form carries no @SInCE token, so check-since-tags never
validated it. New classes (e.g. Biometrics) omit the since marker; do
the same rather than invent a version.
@shai-almog

shai-almog commented Jun 24, 2026

Copy link
Copy Markdown
Collaborator Author

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

Benchmark Results

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

Detailed Performance Metrics

Metric Duration
SIMD kernel backend SSE2 (x64) / NEON (arm64) native kernels
SIMD int-add (64K x300) java 54ms / native 3ms = 18.0x 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 287.000 ms
Base64 CN1 decode 206.000 ms
Base64 native encode 894.000 ms
Base64 encode ratio (CN1/native) 0.321x (67.9% faster)
Base64 native decode 651.000 ms
Base64 decode ratio (CN1/native) 0.316x (68.4% faster)
Base64 SIMD encode 55.000 ms
Base64 encode ratio (SIMD/CN1) 0.192x (80.8% faster)
Base64 SIMD decode 47.000 ms
Base64 decode ratio (SIMD/CN1) 0.228x (77.2% faster)
Base64 encode ratio (SIMD/native) 0.062x (93.8% faster)
Base64 decode ratio (SIMD/native) 0.072x (92.8% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 26.000 ms
Image createMask (SIMD on) 19.000 ms
Image createMask ratio (SIMD on/off) 0.731x (26.9% faster)
Image applyMask (SIMD off) 171.000 ms
Image applyMask (SIMD on) 210.000 ms
Image applyMask ratio (SIMD on/off) 1.228x (22.8% slower)
Image modifyAlpha (SIMD off) 190.000 ms
Image modifyAlpha (SIMD on) 150.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.789x (21.1% faster)
Image modifyAlpha removeColor (SIMD off) 163.000 ms
Image modifyAlpha removeColor (SIMD on) 190.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 1.166x (16.6% slower)

@github-actions

github-actions Bot commented Jun 24, 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)
    • 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 Jun 24, 2026

Copy link
Copy Markdown
Collaborator Author

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

Benchmark Results

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

Build and Run Timing

Metric Duration
Simulator Boot 75000 ms
Simulator Boot (Run) 1000 ms
App Install 11000 ms
App Launch 5000 ms
Test Execution 449000 ms

Detailed Performance Metrics

Metric Duration
SIMD kernel backend SSE2 (x64) / NEON (arm64) native kernels
SIMD int-add (64K x300) java 58ms / native 3ms = 19.3x speedup
SIMD float-mul (64K x300) java 64ms / native 3ms = 21.3x 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 455.000 ms
Base64 CN1 decode 384.000 ms
Base64 native encode 837.000 ms
Base64 encode ratio (CN1/native) 0.544x (45.6% faster)
Base64 native decode 336.000 ms
Base64 decode ratio (CN1/native) 1.143x (14.3% slower)
Base64 SIMD encode 55.000 ms
Base64 encode ratio (SIMD/CN1) 0.121x (87.9% faster)
Base64 SIMD decode 65.000 ms
Base64 decode ratio (SIMD/CN1) 0.169x (83.1% faster)
Base64 encode ratio (SIMD/native) 0.066x (93.4% faster)
Base64 decode ratio (SIMD/native) 0.193x (80.7% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 19.000 ms
Image createMask (SIMD on) 2.000 ms
Image createMask ratio (SIMD on/off) 0.105x (89.5% faster)
Image applyMask (SIMD off) 54.000 ms
Image applyMask (SIMD on) 34.000 ms
Image applyMask ratio (SIMD on/off) 0.630x (37.0% faster)
Image modifyAlpha (SIMD off) 66.000 ms
Image modifyAlpha (SIMD on) 35.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.530x (47.0% faster)
Image modifyAlpha removeColor (SIMD off) 168.000 ms
Image modifyAlpha removeColor (SIMD on) 74.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.440x (56.0% faster)

OrientationLockScreenshotTest waited only 2.5s for the simulator to rotate
to landscape, then captured whatever orientation it was in. On starved CI
runners the rotation+layout takes longer, so it snapped the still-portrait
frame and labelled it 'landscape' -> guaranteed mismatch vs the landscape
reference. This is the ~50% 'landscape' flake seen on master's build-ios /
build-ios-metal jobs (e.g. CN1SS warned the landscape capture was a
duplicate of the portrait/DesktopMode image).

Raise the orientation poll budget from 2.5s to 8s (still well under the 30s
native test timeout) so the capture waits for the rotation to actually land.

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

shai-almog commented Jun 24, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 134 screenshots: 134 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 Jun 24, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 134 screenshots: 134 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 Jun 24, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 132 screenshots: 132 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 71ms / native 5ms = 14.2x speedup
SIMD float-mul (64K x300) java 72ms / native 4ms = 18.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 281.000 ms
Base64 CN1 decode 170.000 ms
Base64 SIMD encode 150.000 ms
Base64 encode ratio (SIMD/CN1) 0.534x (46.6% faster)
Base64 SIMD decode 131.000 ms
Base64 decode ratio (SIMD/CN1) 0.771x (22.9% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 37.000 ms
Image createMask (SIMD on) 16.000 ms
Image createMask ratio (SIMD on/off) 0.432x (56.8% faster)
Image applyMask (SIMD off) 58.000 ms
Image applyMask (SIcaptureWindowToPngBytes window target is not WIC-backed

The web-map test waited a fixed 8s for the Google Maps JS to load tiles
before capturing. On a starved CI runner (88s simulator boot, 450s suite
execution) the live map had not painted a single tile in 8s, so the test
captured a blank grey page -> ~66% mismatch vs the baseline (well past the
35% live-noise tolerance), which the test correctly rejects as a blank map.
build-ios-metal got a healthier runner and the same test passed.

Raise the pre-capture load wait from 8s to 22s (still under the 30s native
test timeout) so slow runners have time to actually render the map. Same
class of capture-before-async-content-ready flake as the landscape fix.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@shai-almog shai-almog merged commit 7db6667 into master Jun 25, 2026
49 of 50 checks passed
@shai-almog shai-almog deleted the feature/device-integrity-rasp branch June 25, 2026 02:38
shai-almog added a commit that referenced this pull request Jun 26, 2026
…s, integrity) (#5289)

* Blog: weekly release series (analytics, maps, TV, editors, integrity)

Adds the weekly release blog series for the 2026-06-26 cycle: a parent
roundup framed around funding open source without the "bait and switch"
(GPL+CE + optional SPI-backed paid services), plus five feature follow-ups.

Posts (docs/website/content/blog):
- funding-open-source-without-the-bait-and-switch (parent, Fri)
- vector-and-native-maps (Sat) - PR #5264
- rich-text-and-code-editing (Sun) - PR #5272
- privacy-first-analytics (Mon) - PR #5266
- apple-tv-and-android-tv (Tue) - PR #5261
- device-integrity-and-app-review (Wed) - PRs #5277 / #5268
Thursday's Game Builder tutorial 2 already exists and is linked.

Each post carries a generated hero image, real in-body screenshots
(maps, editors, app-review widget, a 4K Apple TV ChatView render) and/or
a mermaid diagram. All code samples were verified against the merged
source APIs (MapView/MapStyle, the Analytics SPI + consent gate,
CodeEditor/RichTextArea, DeviceIntegrity, AppReview) and the CSS uses the
real @media device-tv / device-watch syntax.

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

* Blog: fix prose-gate findings (accept-list, vocab, typography, sentence starts)

Resolve the 30 net-new blog-prose-gate findings:
- LanguageTool accept-list: leanback, Classpath, relicense, forkable,
  kotlin, dogfood
- Vale CodenameOne vocab: facade (suppresses proselint.Diacritical)
- mermaid node labels read as prose, so Analytics.event(...) -> event()
- reword four parent sentences that began with a {{< post-link >}}
  shortcode (stripped before lint -> lowercase sentence start)
- Oxford comma, 320x180 -> 320x180 (x sign), 'and so on' -> 'among others',
  'to snapshot' reworded

Vale runs clean (0 findings) locally on all six posts.

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

* Blog: revise series per review feedback

Parent: fix the 'every service ships behind an SPI' claim (services are
optional, we win on integration depth, e.g. crash protection via the build
servers); correct the 'We Will Not Sabotage Your Code' callback (weeks, not
years); drop 'genuinely/honest'; note analytics is included down to the basic
tier with data retention as the gate; non-Google-Play maps differentiator;
banking-customer hardening for DeviceIntegrity; respectful TeaVM/JS-port
wording, drop undocumented 'local-javascript', JS port now aligned and in
final production-ready stages; 'feature deep-dives' instead of links 'going
live'; comments-below for feedback.

Analytics: add the first-party backend section with two console screenshots
(Overview KPIs, Events, Segments, User flow, Goals, Reports), built-in
purchase events and goals; drop 'honest'.

Maps: de-cringe opener, stop overstating peer z-order, refocus on vendor
lock-in without deriding native maps, native-Mac screenshot attribution,
'code still works', drop the iOS-sim validation line, 'The tradeoff'.

Editors: remove the iOS transparent-webview anecdote and 'We did run the thing'.
TV: remove the TVOS_PORT.md guards aside. Device: trim the guarantee sentence,
drop the 'I promised' opener.

Vale runs clean (0 findings) locally on all six posts.

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

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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