Skip to content

[ARCHIVE — DO NOT MERGE] Snapshot of main before force-reset to 2.2.4 - #103

Draft
JakubMrozek wants to merge 46 commits into
v2.2.4-basefrom
archive/main-pre-2.2.4
Draft

[ARCHIVE — DO NOT MERGE] Snapshot of main before force-reset to 2.2.4#103
JakubMrozek wants to merge 46 commits into
v2.2.4-basefrom
archive/main-pre-2.2.4

Conversation

@JakubMrozek

Copy link
Copy Markdown
Member

⚠️ Do not merge — archive / reference only

This PR exists only to preserve and document the state of main (0f46b6a) before we force-reset main to the minimal, v2.2.1-based 2.2.4 line (see #102). It keeps this work visible and reachable so nothing is lost.

  • Base: v2.2.4-base (pinned at v2.2.1) — so the diff below is exactly what main accumulated on top of production.
  • Head: archive/main-pre-2.2.4 = current main.
  • 46 commits preserved.

Why we're doing this

The 2.2.4 release is being rebuilt from the known-good v2.2.1 tag with only the necessary SKAN code, to minimize regression risk on Chai's WebView setup. main will later be force-reset to that line. This archive guarantees the current main work survives and can be cherry-picked back afterward.

Worth cherry-picking back onto the new main (later)

  • #97 Suppress ERR_BLOCKED_BY_ORB noise from ad creatives
  • EXT-229 Defer ATT request until app becomes active
  • 9814286 evaluateJavascript returns null (WebView fix)
  • 8ebcce1 privacy manifest synced to Swift SDK
  • The full added test coverage (API-layer, widgets, services, models, device_app_info)
  • Dev docs: CLAUDE.md, DEVELOPMENT.md, RELEASING.md
  • CI/chore setup (dependabot, Claude Code, etc.)

Not to carry over

  • EXT-175 Flutter 3.38 / iOS 13 requirements bump — intentionally dropped for 2.2.4.

Related: #102 (the 2.2.4 release PR).

JakubMrozek and others added 30 commits March 2, 2026 04:09
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Duc Phi Viet <duc.phiviet01@gmail.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…ING.md

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
chore: add Dependabot for monthly pub dependency updates
Bumps [flutter_lints](https://github.com/flutter/packages/tree/main/packages) from 5.0.0 to 6.0.0.
- [Commits](https://github.com/flutter/packages/commits/flutter_lints-v6.0.0/packages)

---
updated-dependencies:
- dependency-name: flutter_lints
  dependency-version: 6.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
test: add tests for utils — extensions, helper_methods, types
…et iOS 13)

Co-authored-by: Duc Phi Viet <duc.phiviet01@gmail.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…sing

docs: add safety review step before release
- GitHub Actions workflow for @claude PR review comments
- PostToolUse hook to auto-format .dart files after edits
- /create-pr skill for branch + commit + draft PR workflow
…-format

docs: update RELEASING.md changelog format guidelines
JakubMrozek and others added 16 commits March 5, 2026 15:23
chore: remove GitHub release step from releasing process
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…rompt

EXT-229 Defer ATT request until app becomes active
AdEvent: enum ↔ string round-trip for every known event, unknown
fallback, payload parsing (top-level code + nested payload for
clicked/viewed/error), null/missing payload handling, malformed
payload swallowed into .unknown, copyWith override semantics, and
the skip-code constants that make up the server contract.

Character: toJson required fields, optional omission, full field
serialisation, additionalProperties merge (including the key-collision
rule where additionalProperties wins).

Message: isUser/isAssistant, toJson uses role.name + ISO-8601 UTC
(converts local DateTime), equality uses (id, role, content) not
createdAt, inequality on each field, identity, non-Message check.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Covers every class under lib/src/device_app_info/ using
TestDefaultBinaryMessengerBinding.setMockMethodCallHandler to stub
platform channels:

- DeviceAudio: empty(), full response decode (volume rounding +
  outputType list), every AudioOutputType mapped, unknown types fall
  back to .other, PlatformException → empty, toJson omits nulls.

- DevicePower: empty(), full response, every BatteryState, unknown
  state → .unknown, integer level widens to double, exception → empty,
  toJson uses enum name.

- DeviceNetwork: empty(), full decode, every NetworkType, unknown →
  null, exception → empty, toJson emits enum name + omits nulls.

- DeviceScreen: empty() zeros + portrait default, init() returns
  non-negative dimensions under the test binding, toJson shape.

- DeviceHardware: empty(), toJson type pass-through, init() does not
  throw under the test binding (DeviceType varies by host platform,
  so assert isA<DeviceType> rather than a specific case).

- OperationSystem: empty(), init() returns well-formed OS info under
  the test binding, exception fallback to empty.

- AppInfo: empty() + safe defaults, init() does not throw under the
  test binding, storeUrl remains null on non-iOS/Android hosts.

- DeviceAppInfo: empty() aggregates sub-empties, toJson shape, toJsonFresh
  invokes screen/audio init, init() is memoised (identity-equal across
  repeated calls).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
TransparencyConsentFrameworkService: full channel mocking —
valid shape, gdpr=0, non-0/1 gdprApplies → null, non-int or
empty/non-string tcString → null, null-response handling, exception
fallback.

SKOverlayService: uses the injectable `isIOS` hook for full coverage —
non-iOS short-circuit, empty-itunesItem short-circuit, forwards skan/
position/dismissible, false-result passthrough, UNSUPPORTED_IOS
swallowed, any PlatformException swallowed, dismiss happy path + non-iOS
short-circuit + error path.

SKStoreProductService: non-iOS short-circuit, channel forwarding,
native false/throw cases, dismiss paths.

TrackingAuthorizationService: notSupported on non-iOS, enum index
mapping for each TrackingStatus, value-list coverage.

SKAdNetwork and AdAttributionKit: non-iOS short-circuit for every
public method (initImpression/startImpression/endImpression/dispose,
and initImpression/setAttributionFrame/handleTap/beginView/endView/
dispose respectively). The iOS code path is guarded by Platform.isIOS
which cannot be flipped from a Dart test; that coverage lives in the
respective native tests.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
selectBid: placement-not-enabled, code-not-matched, happy path,
relevantAssistantMessageId precedence over lastAssistantMessageId,
not-ready → null, mismatched messageId → null, afterUser branch
(ready/not-ready/mismatch), first-bid-wins when duplicate codes.

useLastMessages hook: empty list resets every setter; assistant-last
emits ids and readyForStreaming=true; user-last sets
readyForStreaming=false; relevantAssistantMessageId resets on a new
user message id; no reset when the id is unchanged.

AdsProviderData: .of returns the nearest ancestor or null;
updateShouldNotify returns false on equal values and true on any
of the tracked field changes (adServerUrl, isDisabled, the two
readyForStreaming flags, each messageId, messages/bids/placements
list, and otherParams map); deep-equal messages list and deep-equal
otherParams do not retrigger.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Drives the full Api → HttpClient → http.Client pipeline end-to-end
with only the outermost http.Client mocked. This proves the wire
contract that publishers rely on.

- happy path: POSTs to /preload, publisher-token and is-disabled
  headers, body fields (publisherToken, conversationId, userId,
  enabledPlacementCodes, messages), bids decoded
- isDisabled=true sends Kontextso-Is-Disabled: 1
- skip:true response propagates to PreloadResponse.skip/skipCode
- network throw falls back to an empty PreloadResponse
- 5xx surfaces statusCode in the response
- TCF platform-channel data is merged into regulatory (gdpr +
  gdprConsent) without clobbering publisher-provided fields (coppa)
- character/variantId/userEmail passthrough
- sessionId persists across consecutive preloads when passed in

Widget-level integration (AdsProvider + messages → triggered preload)
was attempted but ended up flaky because AdsProvider is a HookWidget
that resets HttpClient on mount; reliable simulation of the
hook-driven rebuild + async preload timing in flutter_test is fragile.
The API-layer integration above covers the same HTTP contract with no
timing sensitivity.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- integration_test.dart: drop unused bid.dart import
- message_test.dart: ignore unrelated_type_equality_checks on the
  "Message != non-Message" assertion (the whole point of the test)
- select_bid_test.dart: flip makeData defaults to false/[] so every
  test explicitly opts in to the flag it exercises — removes 7
  avoid_redundant_argument_values warnings

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Expand Dart test coverage 167 → 292 tests
Co-authored-by: Claude Sonnet 4.6 <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.

2 participants