Release 1.0.0 - #11
Open
CoderGamester wants to merge 51 commits into
Open
Conversation
feat(gestures): add swipe and tap detection using Input System refactor(native-ui): migrate to unified namespace and assembly chore(mobile-services): consolidate packages and update to Unity 6 docs(mobile-services): update documentation and add AGENTS.md
…ct state docs: add MIT LICENSE disclaimer to this project
feat(gestures): add TapInput struct for tap detection docs(gestures): update agent guide for new gesture architecture chore(gestures): remove obsolete input abstraction files
Made-with: Cursor
- Add CLAUDE.md + .meta at package root; thin @AGENTS.md import wrapper - AGENTS.md: add Companion-files blockquote - README.md: remove obsolete PointerInputManager / Controls / "Input System Integration" marketing (source uses EnhancedTouch only); document Tap gestures alongside Swipe (TapInput struct, Tapped event); trim to Option B shape (470 -> 210 lines); add Related docs footer Made-with: Cursor
- Add IDeviceService umbrella facade with 8 sub-services: SafeArea, ScreenWake, Battery (with iOS/Android low-power-mode awareness), Connectivity, IosAudioSession, Permissions (unified iOS+Android, Task-based async), App Tracking Transparency (zero ads-ios-support dep), Deep Link (with cold-start link queueing). One shared internal MonoBehaviour host (DeviceServicesHost) for all event-driven children. - Add IHapticsService with 9 cross-platform presets, custom intensity, and time-bounded looping. iOS UI*FeedbackGenerator + Android VibrationEffect bridges, no third-party plugin dependency. - Add NativeUiService.RequestReview() (iOS SKStoreReviewController + Android Play Core In-App Review) and NativeUiService.Share() (iOS UIActivityViewController + Android Intent.ACTION_SEND). - Add 5 iOS native bridges (Att.m, Battery.m, Haptics.m, iOSAudioSession.m, Permissions.m) under Plugins/iOS/. - Add Runtime/AssemblyInfo.cs granting InternalsVisibleTo to both test assemblies for black-box-internal access. - Bootstrap NUnit test suite: 28 fixtures, 106 active tests (75 EditMode + 31 PlayMode), all green. Codify black-box-only testing policy in a new Tests/AGENTS.md (fourth per-package tests guide in the repo, after services/uiservice/gamedata). - Rewrite README/AGENTS/CHANGELOG to document the v1.0.0 surface and gotchas. Co-authored-by: Cursor <cursoragent@cursor.com>
Adds two new rendering surfaces feeding the existing MobileSimulatorState
broker so the truth-mirror mocks can paint right inside Unity's Game /
Simulator view next to the simulated phone screen:
- `MobileSimulatorRuntimeOverlay` (editor-only `[InitializeOnLoad]` bootstrap):
spawns a `[EditorOnly]` `DontDestroyOnLoad` GameObject with a programmatic
`PanelSettings` (`sortingOrder = short.MaxValue`, `ConstantPixelSize`,
`clearColor = false`) carrying a `UIDocument` on `EnteredPlayMode`, tears
down instantly on `ExitingPlayMode`. Opt-in via the new
`MobileServicesSettings.EnableRuntimeSimulatorOverlay` toggle (default OFF,
surfaced under a new "Editor tooling" section in Project Settings). Root
is `pickingMode = Ignore` + `Color.clear` so an empty stage is transparent
to clicks; active mock scrims re-absorb input for modal behaviour.
- `MobileServicesDeviceSimulatorPlugin`
(`UnityEditor.DeviceSimulation.DeviceSimulatorPlugin` subclass): embeds a
slim Control Panel inside Unity's Device Simulator window. Sections per
subsystem (Native UI / Notifications / Device state / Permissions / ATT /
Deep Links) with a top-row "Open full Explorer →" button. Auto-syncs
`MobileSimulatorState.Platform` from `Application.platform` on a 500 ms
`schedule.Execute(...).Every(...)` poll (chosen over
`DeviceSimulator.deviceChanged` due to inconsistently-documented delegate
signature across Unity 6 minor versions). Flips a new
`MobileSimulatorState.IsActivePluginConnected` flag while alive; the
Explorer's `Render as: iOS | Android` dropdown subscribes to
`PluginConnectedChanged` and greys out (+ tooltips) while the plugin
owns the platform skin — handoff is bidirectional and symmetric.
Editor-tooling tests retired: deleted the
`GameLovers.MobileServices.Editor.Tests` asmdef and its 5 test classes
(`EditorPlatformSimulatorTest`, `MobileServicesBuildPostprocessorTest`,
`MobileServicesExplorerWindowTest`, `MobileServicesSettingsTest`,
`MobileSimulatorWindowTest`) plus the `Editor/AssemblyInfo.cs` bridge and
the matching `InternalsVisibleTo("GameLovers.MobileServices.Editor.Tests")`
grant on `Runtime/AssemblyInfo.cs`. Editor tooling is now validated
manually only — codified in `Tests/AGENTS.md` §1 (new "Editor tooling (NOT
tested)" group), §9 (new coverage-gap entry), §11 (new update trigger), and
parent `AGENTS.md` §3 (Tests bullet rewritten). Aligns the package with
what `Tests/AGENTS.md` §10's layout table already implied — `EditMode/Editor/`
was never documented.
Docs: `docs/explorer.md` restructured from "Mobile Simulator Window
(truth-mirror)" into a "Three rendering surfaces" table + per-surface
subsections; stale device-frame line dropped; recommended workflow rewritten
around the Device Simulator + plugin + opt-in overlay; "When to use which"
table extended with a plugin row.
`AGENTS.md`: §2 Editor block describes all three rendering surfaces +
`EnableRuntimeSimulatorOverlay`; §3 Layout convention adds
`Editor/Explorer/DeviceSimulatorPanel/`; §3 `InternalsVisibleTo` paragraph
trimmed; §4 new gotcha entry for the runtime overlay's Play-mode-only,
Editor-asmdef-owned lifecycle; §8 update policy expanded.
`CHANGELOG.md`: folded into the existing `## [1.0.0]` section
(pre-publication versioning rule — no `package.json` version bump) — 2
new `### Added` bullets (Runtime Simulator Overlay, Device Simulator Plugin)
+ new `### Removed` subsection.
Tested: EditMode 790 passed / 0 failed / 1 inconclusive (the documented
`IsOutdatedVersion_DirectInvocation` host-version-parser brittleness);
PlayMode 263 passed / 0 failed. Clean.
Bundled alongside the in-flight v1.0.0 polish work (Phase A-E DX overhaul,
unreleased) that landed in the working tree in a prior session.
Co-authored-by: Cursor <cursoragent@cursor.com>
Replaces the previous "single broker + bidirectional authority handoff"
design (`MobileSimulatorState.IsActivePluginConnected` /
`PluginConnectedChanged` greying out the Explorer dropdown when the
Device Simulator plugin attaches) with per-target routing — resolves
both "Explorer dropdown is greyed when the plugin is alive" and "plugin
clicks paint into the standalone Mobile Simulator window" with one
mechanism. Neither symptom can recur because the surfaces no longer
share state.
Broker (`MobileSimulatorState.cs`):
- New `[Flags] enum SimulatorTarget { None, StandaloneWindow,
RuntimeOverlay, All }` carried by every `Push*`, default `All` so
existing call sites keep broadcast semantics unchanged.
- `Platform` / `PlatformChanged` split into per-surface
`WindowPlatform` (driven by Explorer dropdown) + `OverlayPlatform`
(auto-synced by Device Simulator plugin from `Application.platform`),
each persisted to its own `EditorPrefs` key.
- Every `*Requested` event signature widened to
`Action<SimulatorTarget, TSpec>`. `IsActivePluginConnected` /
`PluginConnectedChanged` removed entirely.
Renderers:
- `MobileSimulatorWindow` subscribes to `WindowPlatformChanged` + filters
every payload event on `SimulatorTarget.StandaloneWindow`.
- `MobileSimulatorRuntimeOverlay` subscribes to `OverlayPlatformChanged`
+ filters on `SimulatorTarget.RuntimeOverlay`.
Producers:
- `MobileServicesExplorerWindow`: dropdown writes `WindowPlatform`,
greying logic gone, dropdown stays interactive forever. Inline italic
scope-hint label + tooltip ("Controls the Mobile Simulator window
only.") with new `.explorer-header-hint` USS rule.
- `MobileServicesDeviceSimulatorPlugin`: every push passes
`SimulatorTarget.RuntimeOverlay` (constant `OverlayOnly`), including
its `Dismiss all mocks` button (was `EditorPlatformSimulator.
DismissAllOverlays()` — broadcast). `SyncPlatformFromHost` writes
`OverlayPlatform` only.
- `EditorPlatformSimulator` untouched — programmatic API stays
broadcast-by-default for tests / scripted automation.
UX polish (4 items bundled):
- Plugin: new auto-hiding `msp-overlay-hint` amber banner inside the
Control Panel surfaces the runtime-overlay precondition
(`EnableRuntimeSimulatorOverlay = true` AND play mode) with a
one-click `Open Project Settings →` jump button. Same 500 ms poll
that re-syncs the platform also refreshes the banner so it
auto-hides the moment both preconditions are satisfied. Without it,
the overlay-scoped routing made it look like the buttons did
nothing in edit mode / when the setting was OFF.
- `NativeUiTab`: new `MakePrimaryButtonRow(params Button[])` helper
wrapping primary buttons so they shrink-wrap to natural width
(matching the Alerts pair) — applied to Toast / Review / Share +
the Alert pair refactored through it for consistency.
- `NativeUiTab`: Toast `Long duration` toggle text now interpolates
`(3.5s vs 2.0s)` from new `ToastShortSeconds` / `ToastLongSeconds`
constants and carries a tooltip mapping to Android's
`Toast.LENGTH_SHORT/LONG` (iOS fakes the toast and reuses the same
timings for editor preview parity).
- `NativeUiTab`: `Show Action Sheet` button greys out reactively when
`WindowPlatform == Android` with an OS-contract tooltip explaining
Android has no native action-sheet idiom (both shapes collapse to
the same Material 3 dialog on a real device). Subscribes to
`WindowPlatformChanged` and unsubscribes via
`RegisterCallback<DetachFromPanelEvent>`.
Docs:
- `AGENTS.md` §2: Explorer dropdown + simulator-broker paragraphs
rewritten for the per-surface scope ("two renderer surfaces, one
broker" + per-target routing); plugin paragraph "scoped to
RuntimeOverlay" + new precondition-banner sentence.
- `docs/explorer.md`: Explorer intro + "Three rendering surfaces" +
Device Simulator plugin section + "Acknowledged overlap" platform-
toggle row all rewritten for the per-target model.
- `CHANGELOG.md`: folded into existing `## [1.0.0]` section per
pre-publication versioning rule (verified `git tag --list` shows
no v1.0.0 tag yet) — terse user-facing bullets only.
Editor tooling validated manually only per `Tests/AGENTS.md` §1 — no
automated tests touched.
Co-authored-by: Cursor <cursoragent@cursor.com>
…ervice Delete the Mobile Services Explorer window, the standalone Simulator window, all Explorer tabs + base, and the ConnectivityService (+interface and its test) as part of consolidating editor tooling onto the Device Simulator plugin.
… Simulator plugin Make the Device Simulator plugin the single editor surface and the in-Game overlay the single canvas (edit + play mode). Collapse the simulator broker to one Platform skin, redesign the notification heads-up mock + add a Painter2D intensity-over-time haptics curve, and reduce the panel to mock previews + state-setting controls (Permissions/ATT state dropdowns, play-mode gating with per-section banners). Add runtime-settable INotificationService.Mode and drop ConnectivityService from the IDeviceService umbrella. Update tests, samples, and docs to match. Co-authored-by: Cursor <cursoragent@cursor.com>
…panel Add an "Editor Simulator" header toggle (MobileSimulatorState.Enabled, persisted to EditorPrefs) that enables/disables every panel section as a group and shows/hides the in-Game-view [EDITOR SIMULATOR] banner; turning it off clears any visible mock. Replace the global "Dismiss all mocks" button with per-section dismiss buttons: "Dismiss all UIs" in Native UI and "Dismiss Banner" in Notifications. Co-authored-by: Cursor <cursoragent@cursor.com>
…ication service surface Adds 10 black-box/gray-box tests filling Editor-runnable coverage gaps found by the tests audit (no P0 gaps; all platform/native paths remain documented manual-only Skips per Tests/AGENTS.md §9): - EditMode: HapticsService default ctor (Editor backend selection) and NotificationBuilder Subtitle/Id/SmallIcon/LargeIcon fluent setters. - PlayMode: MobileService/DeviceService default-ctor child wiring (new files), BatteryService/SafeAreaService default ctors, and MobileNotificationService Mode round-trip, empty PendingNotifications, and the two delivery/expiry events not firing on Editor schedule. All 165 tests pass (128 EditMode + 37 PlayMode). Co-authored-by: Cursor <cursoragent@cursor.com>
The Device Simulator Permissions/ATT controls were instant state-setters; they now reproduce the on-device flow: the first runtime RequestAsync() / RequestAuthorizationAsync() on a NotDetermined entry shows the native-style prompt in the in-Game-view overlay and resolves the Task on answer, then the decision is cached (EditorPrefs) so repeat requests never re-prompt. The dropdowns are the Settings surface; reset re-arms the prompt. - Add editor-only EditorRequestAsyncOverride hooks to PermissionsService and AttService (precedence over the sync override; no-override default unchanged). - Add EditorPrefs-backed NotDetermined decision store + Engage/Disengage and prompt-once-then-cache request handlers (usage text from MobileServicesSettings) in EditorPlatformSimulator; ATT prompts under the iOS skin only. - Panel: dropdowns write the store (ungated), NotDetermined reset buttons, and a play-mode Allow/Deny fallback for resolving a pending prompt. - Surface Permissions/ATT guidance in a highlighted banner; lift user-facing panel copy into constants. - Update AGENTS.md, docs/explorer.md, CHANGELOG (Unreleased).
…cesConfig Native UI / review: - RequestReview() stays OS-native (iOS SKStoreReviewController, Android Play In-App Review); fire-and-forget with request/launch logging and a warning/error when the Play flow cannot run (no store-URL fallback). - Device Simulator renders a faithful per-platform review mock (iOS centered star sheet / Android Play bottom sheet), shown only when game code calls RequestReview() via the EditorRequestReviewOverride hook (no panel trigger). - Auto-inject the Play In-App Review Gradle dependency via IPostGenerateGradleAndroidProject (default on, conflict-safe, editable coordinate) so RequestReview() works zero-config on Android. - Prefix iOS exports _GameLoversAlertMessage / _GameLoversToastMessage to avoid duplicate-symbol linker collisions. Config refactor: - Replace the MobileServicesSettings ScriptableSingleton with an editor-only MobileServicesConfig ScriptableObject (Instance locator + custom Inspector + "Tools > GameLovers > Mobile Services > Select Mobile Services Config"). - Emit per-locale iOS usage descriptions as <locale>.lproj/InfoPlist.strings + CFBundleLocalizations for true device-language localization. - Trim over-engineering: drop BackgroundAudio (Unity Player Settings owns it), placeholder soft-mode (validation is now fail-fast), BuildCallbackOrder, EnableRuntimeSimulatorOverlay, and ScanPopulatedCapabilities; rename DisableBuildPostProcessing -> ManageNativeBuildManually. Docs: - Fix stale IMobileService comments (remote notifications / connectivity). - Rewrite the 1.0.0 CHANGELOG (Unreleased) and update AGENTS / README / docs. Co-authored-by: Cursor <cursoragent@cursor.com>
…ty 6 API updates SerializableNotification uses explicit has-value flags for nullable fields so background-rescheduled notifications keep their delivery time. SafeAreaContainer migrates to [UxmlElement]; simulator uses FindAnyObjectByType. Co-authored-by: Cursor <cursoragent@cursor.com>
Folds into the existing CHANGELOG [1.0.0] section -- 1.0.0 is unreleased (max tag 0.2.5). No package.json version bump. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adds (or updates) Tests/AGENTS.md and its Tests/CLAUDE.md wrapper, and points the package-root AGENTS.md at it as required reading before touching Tests/. Sections 1-2 (ADMIT test-admission criteria, RCR revert-and-confirm-red) are shared verbatim across all six GameLovers packages and must be changed in lockstep. This revision anchors mutation references on file + symbol rather than file:line, which rots, and caps the on-test comment budget - change narration and investigation transcripts belong in the commit body, not on the test. No test or production code changes in this package. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ed §2) §2 declared any test without an RCR line "suspect by default", but some correct tests provably have no one-line mutation - double-guarded validation, where an unconfigured object trips two independent guards so disabling either leaves the other throwing. The rule was mislabelling tests that are right and unbreakable. Adds an UNFALSIFIABLE exemption on §13's terms: the reason must be falsifiable, must name both guards, and must record that a mutation was tried and observed green. "Couldn't find one" is explicitly not a reason - that is an unfinished RCR, not an exemption. Also adds a verdict table for tests that resist mutation, because they are not one problem: A5 duplicates get deleted (naming the surviving sibling), D2 overclaims get a strengthened assertion or an honest rename, and UNFALSIFIABLE tests are kept with the exemption comment. The class must be proven before acting - an A5 duplicate by observing the sibling's mutation redden both, a D2 overclaim by observing the implied mutation leave the test green. §1 and §2 remain byte-identical across all six packages. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Section 2's verdicts table gains a fourth class. UNFALSIFIABLE was absorbing tests that section 1's A3 rule would never have admitted - the tell being reasons like "no line in Runtime/ participates" or "these are C#'s zero-init values", which describe a test that pins nothing rather than one that is hard to break. New rule: if no line in Runtime/ or Editor/ participates in the assertion, it is an A3 reject and the verdict is delete. UNFALSIFIABLE stays reserved for behaviour this package genuinely owns but cannot be broken one line at a time. Sections 1-2 are shared verbatim across all six Tests/AGENTS.md; no test or production changes in this package. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Section 13 now carries a dated baseline for this package's runtime assembly, plus the reason to steer by that number rather than the combined one. Every earlier coverage figure in this repo was an artifact and must not be compared against: - reports before today ran without -debugCodeOptimization, so Unity compiled Release and emitted ~40% fewer sequence points (MathfloatP showed 637 coverable lines instead of 1002) - a silently shrunken denominator - some runs leaked test and sample assemblies into scope, and some covered only 3 of the 6 packages The current run covers all 11 production assemblies with none leaking, verified via the MathfloatP denominator check now documented in Tools/coverage.sh. Repo-wide: runtime 73.9%, Editor 5.5%, combined 41.0%. Editor is 48.1% of all coverable lines and is accepted-untestable per the ACCEPTED (iii) rows in section 13, which is the whole reason the combined figure is not the one to track. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sections 1-2 are shared verbatim across all six packages; this adds a sixth admission question and the worked instance behind it. A6 asks whether an assertion's outcome would change if project configuration changed - a renderer feature installed or removed, an Addressables catalog built, a sample imported. If so the test must READ that state rather than assume one value of it. A6 is not A3. A3 asks whether the package computed the value; A6 asks whether the test assumed which value it would be. A test can satisfy A3 and still fail A6, which is exactly how the gap went unnoticed: UiBackdropBlurPresenterFeatureTests read a package-computed flag (UiBackdropBlurRendererFeature.IsInstalled) but hard-coded the expectation that it was false. Batchmode never instantiates the URP renderer, so the flag was false there and all five tests passed; in the Editor the feature registers from the project's renderer asset and all five failed. The fixture was asserting a fact about the repo, not about the code under test. Validated against the existing corpus before being written, per root AGENTS.md 2.2: the blur fixture was the only violation and is already fixed. AddressablesUiAssetLoaderTests asserts on a key that is unresolvable either way, and UiCameraStackFeatureTests builds its own cameras rather than reading project renderer state. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
86 of 86 mutations observed RED and reverted; all production files byte-identical afterwards. Full EditMode suite green at 826/826. 24 EditMode tests were deliberately left without a mutation rather than given an invented one, classified with evidence: - A3 reject (11): auto-property round-trips, struct zero-init, an Assert.Pass() body, and two notification tests where nothing in the editor ScheduleNotification branch can fire the event being counted. - A5 duplicate (8): the four NativeUiServiceInstance *_DoesNotThrowInEditor tests die only on the same editor short-circuit as their NativeUiServiceTest siblings, which additionally assert the log text; the two DefaultCtor_UsesSharedHost tests are one-line delegations to Instance. - D2 overclaim (3): DefaultCtor_InEditor_SelectsEditorBackend_NotSupported cannot distinguish the backend it names (NoOpHapticsBackend satisfies all three assertions identically); Dispose_UnregistersAllHostHandlers never observes an unregistration. - UNFALSIFIABLE (3) and Smoke-exempt (1), each with the reason recorded on the test. A6 exposure worth acting on separately: five tests read process-wide editor statics they never establish - PermissionsService/AttService overrides, plus BatteryService.EditorLowPowerModeOverride and NativeUiService.EditorRequestReviewOverride. They assert the bare-editor default and pass only while nothing has engaged the Device Simulator. Tests/AGENTS.md section 13 already carries an OPEN row for the first two; the latter two should be added to its owed SetUp/TearDown reset. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
27 mutations; 24 RED first pass, and the 3 that produced no report were all MY bad mutations rather than test failures. All three shared one root cause worth recording: Flipping `||` to `&&` on a `!int.TryParse(a, out var x) || !int.TryParse(b, out var y)` guard breaks C# definite-assignment analysis - with `&&` the second TryParse only runs when the first succeeds, so `y` is not assigned on every path reaching the code below, and the file fails to compile with CS0165. The harness surfaces that as "no report after 3 attempts", which reads like a hang rather than a compile error. The working form uses non-short-circuit `|` so both out variables are always assigned, then `& false` to disable the guard: if ((!int.TryParse(idText, out var id) | !int.TryParse(statusText, out var statusInt)) & false) All three then went RED-OK and isolated. EditMode 826/826, PlayMode 299/299. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…hotting MobileNotificationService's ctor assigned the backing fields of its two field-like events into GameNotificationsMonoBehaviour's plain Action fields. Both were null at that point, so the host held a null snapshot forever: every later `service.OnLocalNotificationDeliveredEvent += handler` mutated the service's own field while the host kept invoking null. On device, delivered and expired callbacks never reached a consumer. Both are now forwarded through a lambda, so subscribers attached after construction are reached. Adds two PlayMode tests. The expired one drives the real raise site (Mode=Queue + a past DeliveryTime, expired by the host's Update); the delivered one raises through the host's public field, because OnNotificationReceived is platform-driven and the Editor has no IGameNotificationsPlatform. RCR STATUS: PENDING — neither mutation has been observed red. The Unity project lock is owned by a central verifier, so no test runner was invoked for this change. Both tests carry `// RCR: PENDING` comments naming the exact one-line revert; they are not trusted coverage until that run happens. RCR: OnLocalNotificationDeliveredEvent_SubscribedAfterCtor_ReachesSubscriber <- MobileNotificationService.cs ctor, restore `= OnLocalNotificationDeliveredEvent` (PENDING) RCR: OnLocalNotificationExpiredEvent_SubscribedAfterCtor_ReachesSubscriber <- MobileNotificationService.cs ctor, restore `= OnLocalNotificationExpiredEvent` (PENDING) Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Deleted (A3 - the assertion reads no value this package computed): - AlertButton_FieldRoundTrip: AlertButton is a three-public-field struct with no logic. - ImplementsInterface: a class declaration; removing it is a compile error, not a red. - AllProperties_RoundTripGettersAndSetters and Scheduled_DefaultsFalse: bare auto-properties, and Scheduled is get-only and never assigned in Runtime/. - Reschedule_DefaultsFalse: a plain public field with no writer in Runtime/. - IsPlaying_FalseInitially's sibling set retained; see below. KEPT: Dispose_DoesNotThrow_AndPendingColdStartLinkIsNull, classified A5 but never probed. Across the repo, 7 of 10 probed A5 candidates turned out to have unique pins, so unprobed A5 claims are not acted on. EditMode 806/806, PlayMode 295/295. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Both mutations were run and observed red; the comments no longer say PENDING. Batchmode PlayMode, filtered to MobileNotificationServiceTest (12 tests): baseline 12 passed 0 failed mutant-delivered 11 passed 1 failed <- delivered test only mutant-expired 11 passed 1 failed <- expired test only restored 12 passed 0 failed Each test reddens on its own ctor line and stays green under the other's mutation, so neither is an A5 duplicate of the other. Both failed on the assertion (Expected: same as PendingNotification, But was: null), not by NullReferenceException, so this is the test asserting rather than crashing. Batchmode only. Neither test touches URP, Addressables or imported samples, so no Editor-half divergence is expected, but the Editor half of Tools/test-all.sh has not been run. RCR: OnLocalNotificationDeliveredEvent_SubscribedAfterCtor_ReachesSubscriber <- MobileNotificationService.cs ctor, restore `= OnLocalNotificationDeliveredEvent` -> RED RCR: OnLocalNotificationExpiredEvent_SubscribedAfterCtor_ReachesSubscriber <- MobileNotificationService.cs ctor, restore `= OnLocalNotificationExpiredEvent` -> RED Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…it proved First trustworthy coverage figure for this repo. Regenerated with -debugCodeOptimization, all 11 GameLovers assemblies in scope, test and sample assemblies excluded. Repo-wide runtime coverage is 74.1% (6609/8922). Do not compare against any earlier number. 41.8% was stale, wrongly scoped to 6 assemblies, and diluted by Editor code; 38.3% was compiled in Release, which silently shrank the denominator ~40%. The register now names the sanity check that catches a repeat: MathfloatP must report ~1002 coverable lines, not 637. The OPEN rows added here are findings the mutation pass PROVED rather than suspected - each one is a mutation that was applied and observed leaving its test green. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…r statics The four NativeUiServiceInstance tests asserted only DoesNotThrow; they now assert the forwarding to the static service, and each reddens in isolation. Two fixes avoid introducing a NEW A6 coupling while removing an old one: - Dispose_UnregistersAllHostHandlers compares against the value captured before driving the host, rather than asserting the bare-editor default of EditorLowPowerModeOverride. - DefaultCtor_RegistersOnSharedHost (renamed) sets EditorLowPowerModeOverride = false itself before constructing, and resets it in a finally. That static is a live section 13 OPEN row; the test now establishes the state instead of inheriting it. BatteryServiceTest gains #if UNITY_EDITOR guards: the PlayMode asmdef has includePlatforms: [], so it compiles for players where EditorLowPowerModeOverride does not exist. The non-editor branch uses Assert.Ignore rather than silently passing. RCR: ShowAlertPopUp/ShowToastMessage/RequestReview/Share_ForwardsToStaticService <- NativeUiServiceInstance.cs each forwarding call (RED, all isolated) RCR: OnPermissionResult_UnknownId_NoOp <- PermissionsCallbackReceiver.cs resolve the wrong pending TCS (RED, isolated) RCR: Dispose_UnregistersAllHostHandlers <- BatteryService.cs Dispose (RED, isolated) RCR: DefaultCtor_RegistersOnSharedHost <- BatteryService.cs parameterless ctor (RED, isolated) EditMode 806/806, PlayMode 295/295. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…e leakage row Ctor_CapturesInitialLevelStatusAndLowPowerMode asserted IsFalse(IsLowPowerMode) while reading BatteryService.EditorLowPowerModeOverride unpinned. It passed only because the two sibling tests that drive the static restore it to false in their finally blocks - an ordering accident, and the A6 pattern of inheriting ambient state rather than establishing it. [SetUp] now pins it false and [TearDown] resets it. That was the last piece of the process-wide editor-static leakage row: NativeUiServiceInstanceTest already nulls NativeUiService.EditorRequestReviewOverride in [SetUp] (9b870e3). The PermissionsService.EditorCheckOverride / AttService.EditorCurrentStatusOverride half remains OPEN in its own row - those three fixtures are untouched. Editor PlayMode 295/295, including all three BatteryServiceTest cases. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
§13 asserted every named symbol was 'either ACCEPTED or OPEN' while four packages had already grown CLOSED rows — the spec forbade rows it contained. CLOSED is now first-class, and it carries a contract: name the commit AND the observation, including the environment the observation came from. A row closed on 'the fix landed' is still OPEN, because the fix is the edit and the closure is the evidence. Second rule: closing a row means re-deriving its claim against current source, never reading the commit that claimed to fix it. A partial fix and a complete one produce the same green suite and the same confident commit message, so the commit cannot be evidence for its own completeness. §1 and §2 are shared verbatim across all six packages; §13's preamble is too. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
CS0618: FindObjectsByType<T>(FindObjectsSortMode) is deprecated. ResolveHost filters by reference equality, so ordering is irrelevant and the parameterless overload is a direct replacement. Surfaced by taking warning counts from a -runTests log rather than a plain editor open: test assemblies carry defineConstraints UNITY_INCLUDE_TESTS and are not compiled by a normal open, so warnings in test code never appeared. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… unowned-edit measurement Tests/AGENTS.md section 2 said a test with no // RCR: line is a suspect by default, without carving out Smoke/. Section 1 already exempts that directory (its defect class is "the assembly no longer loads", which has no one-line mutation), so the omission flagged those fixtures forever. Exemption is now explicit, on the same directory basis. Also records that "unannotated" is three states, not one: observed RED with the write-back lost, seen reddening only as collateral, or never probed. Only the last needs a probe, and prepared annotation text must never be written without a matching RED-OK - it exists for tests that were never probed, and writing it fabricates a verified claim. Adds a section 13 row for the measured count of production edits that redden only collaterally (223 repo-wide, from .test-all/rcr/unowned-edits.json). Recorded with the caveat that it is NOT that many missing tests: for foundational primitives and the UiService integration hub, having no isolated owner follows from centrality, not neglect.
Mechanical pass, no behaviour change. - Converted 23 enum members to inline `//` comments (HapticPreset, NotificationStyle, PrivacyMode, OperatingMode), per §6.6's rule that enum values never carry `/// <summary>`. OperatingMode's members had multi-sentence summaries that would have become 250-character lines, so their caveats — badge auto-increment only when nothing sets one explicitly, and RescheduleAfterClearing being meaningful only alongside ClearOnForegrounding — moved to a <remarks> on the enum instead. - Removed the doc comments from 21 constructors and from the private ActiveGesture.accumulatedNormalized field. - Converted 7 private-member doc blocks to `//` comments rather than deleting them, keeping their rationale where §6.6 forbids `///`. - Dropped <param>/<returns>/<exception> from the internal IGameNotificationsPlatform and ActiveGesture.SubmitPoint. The <exception> tags on both ScheduleNotification overloads documented real behaviour, so that is folded into their <summary> rather than lost. - Added `/// <inheritdoc />` to the three MobileServicesDeviceSimulatorPlugin overrides (external Unity base). - Moved the internal editor/test seams above their types' private blocks (§6.6: `internal` is never interleaved with `private`): SafeAreaService.SimulateSafeAreaChanged, DeepLinkService.SimulateLinkActivated, BatteryService.SimulateLowPowerModeChanged, and MockBuilders' BuildReviewPrompt / BuildPermissionDialog / BuildNotificationBanner. Verified: Tools/style-audit.py reports 0 for every mechanical rule class (A/B/C/D/K/N) across all six packages. For each reordered file the sorted non-blank line multiset is unchanged against HEAD, proving the moves are pure reorders; `#if`/`#endif` counts stay balanced; and every file's UTF-8 BOM still matches HEAD. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Two sentences, neither earning its place on a private nested class: the first
restated what `OverlayController` already says, and the second ("Same renderer
surface the standalone window used to provide") was change narration about a
window removed in the 1.0.0 consolidation — which §6.6's Code comments rule
forbids outright.
§6.6 now states that a comment on a private member is a last resort and that
removing a `///` block is not a licence to leave a `//` in its place.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Completes this package — Tools/style-audit.py reports 0 items. Documented the NotificationBuilder fluent setters (which are iOS-only, and that an explicit BadgeNumber opts the notification out of the auto-increment path), the MobileSimulatorState payload types / events / push entry points, the MockBuilders factories, the DeviceServicesHost unregister pairs, the SerializableNotification round-trip and its nullable value+flag flattening, plus TapInput, AlertButton / AlertButtonStyle, ProjectScanResult.ReferencedPermissions and the two callback-receiver singletons. The three UnitySendMessage entry points — OnIosLowPowerModeChanged, OnPermissionResult, OnAttResult — now state in their summaries that they must stay public and keep their exact names, because the iOS bridges in Plugins/iOS/*.m dispatch them by string. That constraint previously lived only in a `//` comment on the member, invisible to anyone reading the API. Six single-line summaries on public Runtime methods were expanded to the block form §6.6 requires there; the ones on internal and Editor members stay compact. Verified: batchmode green — EditMode 805/805, PlayMode 295/295, and 0 CS warnings in the -runTests log. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A docs pass rewrote the file with LF, changing every historical byte and breaking the release-notes validator's baseline comparison. Restores the committed convention per AGENTS.md; no content change.
Unity's packer uses .gitignore as its pack-ignore list, so listing .github/ drops the CI workflow from the tarball while git keeps tracking it (gitignore does not untrack existing files). Verified on a real clone: 434 -> 433 entries, .github 1 -> 0, Runtime unchanged.
Unify the four samples into one InputForUI-based bundle, move sample-specific editor workflows into the imported sample, and retain production native build integration in the package. Harden service and gesture lifecycles, connect notification simulation to the sample-owned service, refresh documentation, and expand regression coverage. RCR: Ctor_NullConfigure_Throws ← DeepLinkRouter constructor null guard RCR: Ctor_ConfiguresBeforeSubscription ← DeepLinkRouter constructor subscription order RCR: Ctor_ConfigurationFailure_DoesNotSubscribe ← DeepLinkRouter constructor failure cleanup RCR: Dispose_IsIdempotentAndGuardsOperations ← DeepLinkRouter ThrowIfDisposed RCR: Dispose_DisposesEachDistinctDisposableInstance_Once ← MobileService DisposeChild calls RCR: Dispose_SharedDisposableChild_DisposesOnce ← MobileService reference identity guard RCR: ScreenPixelsToPanelUnits_ScaledPanel_ConvertsInsetToPanelCoordinates ← SafeAreaContainer conversion RCR: OnDisable_AfterEnhancedTouchIsReleased_DoesNotAccessCallbacks ← Smoke lifecycle exemption RCR: OnDisable_WithAnotherControllerEnabled_KeepsEnhancedTouchSupportEnabled ← GestureController balanced Disable RCR: OnPressed_DuplicateFingerDown_DoesNotThrowAndReportsBothPresses ← GestureController OnPressed replacement RCR: Dispose_StopsOutput_DestroysHost_AndIsIdempotent ← HapticsService Dispose RCR: ScheduleNotification_InEditor_AddsReturnedPendingToCollection ← MobileNotificationService scheduling RCR: TrySimulateDelivery_RemovesPendingAndRaisesDeliveredEventOnce ← MobileNotificationService simulation RCR: Dispose_DestroysOwnHost_AndIsIdempotent ← MobileNotificationService Dispose RCR: PublicOperations_AfterDispose_ThrowObjectDisposedException ← MobileNotificationService ThrowIfDisposed RCR: CancelNotification_RemovesPendingNotificationWithoutNativeBackend ← GameNotificationsMonoBehaviour cancellation RCR: CancelAllScheduledNotifications_ClearsPendingNotificationsWithoutNativeBackend ← GameNotificationsMonoBehaviour cancel all RCR: SetSafeAreaService_ScaledPanel_UsesPanelCoordinatesForScreenInset ← SafeAreaContainer Apply
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
New:
Schedule().In(...).Title(...).Body(...).Channel(...).Send()builder.Deviceumbrella service exposes safe area, screen wake, battery and low-power mode, iOS audio session, permissions, App Tracking Transparency, and deep links.ATTrackingManagerbridge with no dependency oncom.unity.ads.ios-support.Application.deepLinkActivatedwrapper with cold-start link queueing for the first subscriber.IDeepLinkServicewith captured parameters such as/promo/:id.IMobileServiceprovides one DI registration for Native UI, Notifications, Haptics, and Device services.INativeUiServiceandNativeUiServiceInstancesupport mockable consumer code.Tools > GameLovers > Mobile Services > Select Mobile Services Config.MobileServicesPlayground,HapticsPalette,NotificationsScheduler, andDeepLinkRouter.Changed:
com.gamelovers.mobileservicespackage name,GameLovers.MobileServices.*namespaces, andGameLovers.MobileServicesassembly.Fixed:
Removed:
TapInteractioninstead.Migration:
This package consolidates three previously separate packages:
com.gamelovers.nativeui(v0.2.5) →GameLovers.MobileServices.NativeUicom.gamelovers.notificationservice(v0.1.7) →GameLovers.MobileServices.Notificationscom.gamelovers.inputextensions(v0.1.0-preview.4, swipe detection only) →GameLovers.MobileServices.GesturesAlertButtonStyle.Positive→AlertButtonStyle.Destructive;AlertButtonStyle.Negative→AlertButtonStyle.Cancel.