Skip to content

Commit 5b862a2

Browse files
committed
feat(flutter): replace capture profiles with capabilities
1 parent e70741a commit 5b862a2

39 files changed

Lines changed: 544 additions & 558 deletions

docs/design/capture-and-fingerprint.md

Lines changed: 21 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@ arbitrary visible text as structural identity.
1515

1616
- State and target identity are deterministic within one build and fingerprint
1717
schema version.
18-
- Exploration and production profiles use the same fingerprint algorithm.
18+
- Optional evidence capabilities use the same fingerprint algorithm.
1919
- Locale is emitted as session and event evidence but never enters identity.
2020
- Developer tags strengthen matching but are optional.
2121
- Screenshots remain visual evidence and are masked before leaving the app.
2222
- Capture failures and sink failures must not interrupt the host app.
23-
- Dormant and disabled modes return the host child unchanged.
23+
- Disabled lifecycle configuration returns the host child unchanged.
2424

2525
Cross-build stability is not promised. Consumers should namespace identity by
2626
build metadata and `fingerprintSchemaVersion`; remapping identities across app
@@ -46,21 +46,20 @@ NavigatorObserver + global/local pointer input + scroll notifications
4646
```
4747

4848
`TugboatReplay.wrapApp` installs the controller, repaint boundary, input
49-
capture, scroll listener, and lifecycle observer only for an active profile.
49+
capture, scroll listener, and lifecycle observer only when capture is enabled.
5050
`TugboatReplay.navigatorObserver` supplies route changes and navigator context.
5151
Both are needed for complete capture.
5252

53-
### Profiles and activation
53+
### Lifecycle and capabilities
5454

55-
| Profile | Implemented behavior |
56-
| --- | --- |
57-
| `dormant` | Always-mounted lightweight gate; no pointer/screenshot/sink machinery until `activate` |
58-
| `exploration` | full interaction capture, scene inventory, and optional emitted semantic maps |
59-
| `productionLean` | interaction capture, no scene-inventory events, production screenshot masking by default |
55+
`TugboatReplayConfig.enabled` controls the capture lifecycle. Scene inventory,
56+
semantic-map, diagnostic, and action-context evidence use separate additive
57+
capabilities. All optional capabilities are false by default. The default
58+
screenshot mask is always `allTextAndMedia`.
6059

6160
`TugboatReplay.disabled = true` is a global kill switch. It deactivates the
6261
current controller and keeps future calls to `wrapApp` inert. Runtime
63-
`activate(activationRequestId:, profile:)` notifies the mounted gate without
62+
`activate(activationRequestId:)` notifies the mounted gate without
6463
requiring a host rebuild. `deactivate()` tears capture down through the same
6564
gate. Pause/hidden flush pending delivery; detach ends the session once.
6665

@@ -261,10 +260,9 @@ the SDK collects mask rectangles using the shared anchor resolver and applies
261260
them as opaque fills on the RGBA buffer inside the encode isolate (avoiding a
262261
second full-size GPU raster).
263262

264-
The default mask policy is profile-dependent:
265-
266-
- `exploration`: explicit `TugboatSensitive` subtrees only;
267-
- `productionLean`: all rendered text, editable inputs, and images.
263+
The default mask policy covers all rendered text, editable inputs, and images.
264+
Hosts can select a stricter or narrower explicit mask policy. Evidence
265+
capabilities never change the mask.
268266

269267
The public mask levels are `explicitOnly`, `allTextAndMedia`, `allText`,
270268
`allTextExceptActionable`, and `sensitiveInputsOnly`.
@@ -336,19 +334,18 @@ device-tier gates.
336334

337335
## Viewport semantics
338336

339-
`viewportSemanticMode` resolves with the capture profile:
337+
`viewportSemanticMode` resolves with `emitViewportSemanticMap`:
340338

341339
| Mode | Engine | Emits map events | Debug logs |
342340
| --- | --- | --- | --- |
343341
| `off` | no | no | no |
344-
| `tapResolutionOnly` | yes for active profiles | no | no |
345-
| `full` | yes | exploration only | no |
346-
| `fullWithDebugLogs` | yes | exploration only | exploration only |
347-
348-
Exploration holds a persistent Flutter `SemanticsHandle` when semantics are
349-
enabled. Production uses transient semantics and never emits semantic-map
350-
events, even in `full` modes; it can still build maps locally for tap
351-
resolution. Emitted exploration maps are bounded by
342+
| `tapResolutionOnly` | yes while enabled | no | no |
343+
| `full` | yes | when capability is true | no |
344+
| `fullWithDebugLogs` | yes | when capability is true | when capability is true |
345+
346+
The SDK holds a persistent Flutter `SemanticsHandle` only while semantic-map
347+
emission is enabled. It can still build maps locally for tap resolution.
348+
Emitted maps are bounded by
352349
`viewportSemanticMapMaxNodes` (default `120`) and
353350
`viewportSemanticMapMaxBytes` (default `48000`).
354351

@@ -412,7 +409,7 @@ Unit thresholds live in `benchmark/screenshot_budget_baseline.dart`. The default
412409
rolling budget is 60 ms per 5 s window so eligible captures skip under load
413410
sooner now that paint-generation / dHash coalesce replace the old post-capture
414411
state-signature short circuit. Record multi-tier device measurements before
415-
enabling more aggressive degradation in production profiles.
412+
enabling more aggressive degradation in normal app capture.
416413

417414
### 3. Deferred capture surfaces
418415

docs/integration/collector.md

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ Transport failures are isolated from the host app.
1414

1515
## Required app integration
1616

17-
Install the wrapper and navigator observer. Capture is dormant by default, so
18-
select an active profile for startup capture:
17+
Install the wrapper and navigator observer. Capture is dormant by default.
18+
Set `enabled: true` for startup capture, or call `TugboatReplay.activate` later:
1919

2020
```dart
2121
MaterialApp(
@@ -27,6 +27,10 @@ MaterialApp(
2727
);
2828
```
2929

30+
The default configuration masks all text and media. Optional inventory,
31+
semantic-map, diagnostic, and action-context evidence stays off until the host
32+
enables each matching capability.
33+
3034
Without the observer, pointer and scroll evidence still works but route-change
3135
events and route-backed anchors are incomplete. Without the wrapper no capture
3236
controller or transport is installed.
@@ -42,7 +46,10 @@ Use the exploration destination for an interactive local run:
4246

4347
```dart
4448
const config = TugboatReplayConfig(
45-
profile: TugboatCaptureProfile.exploration,
49+
enabled: true,
50+
emitSceneInventory: true,
51+
emitViewportSemanticMap: true,
52+
acceptActionContext: true,
4653
explorationCollectorUrl: 'ws://127.0.0.1:7832/sdk',
4754
explorationRunId: 'optional-run-id',
4855
appInfo: TugboatCollectorAppInfo(
@@ -115,7 +122,7 @@ final collector = await TugboatCollectorHost.fromPlatform(
115122
);
116123
117124
final config = TugboatReplayConfig(
118-
profile: TugboatCaptureProfile.productionLean,
125+
enabled: true,
119126
collector: collector,
120127
);
121128
```
@@ -301,7 +308,10 @@ stamping or clearing a newer session's evidence.
301308

302309
```dart
303310
final config = TugboatReplayConfig(
304-
profile: TugboatCaptureProfile.exploration,
311+
enabled: true,
312+
emitSceneInventory: true,
313+
emitViewportSemanticMap: true,
314+
acceptActionContext: true,
305315
explorationCollectorUrl: 'ws://127.0.0.1:7832/sdk',
306316
collector: productionCollectorConfig,
307317
);

docs/releases/compatibility.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@
22

33
| Adapter | Adapter version | Native runtime |
44
| --- | --- | --- |
5+
| Flutter `tugboat` | 0.9.0 | Android `capture-runtime` `0.1.0`; Apple `TugboatCaptureRuntime` `0.1.1`; mode-free capture API with additive evidence capabilities. |
56
| Flutter `tugboat` | 0.8.17 | Android `capture-runtime` `0.1.0`; Apple `TugboatCaptureRuntime` `0.1.1`; blank iOS engine captures retry with explicit hierarchy coverage. |
67
| Apple `TugboatCaptureRuntime` | 0.1.1 | Rejects transparent and near-white captures and validates explicit view-hierarchy capture before encoding. |
78
| Flutter `tugboat` | 0.8.16 | Same hosted runtimes as 0.8.15. iOS plugin looks up `registrar.viewController` at runtime so Flutter 3.35 hosts compile. |
89
| Flutter `tugboat` | 0.8.15 | Android `com.gettugboat.sdk:capture-runtime:0.1.0` from Maven Central. Apple `TugboatCaptureRuntime` `0.1.0` from CocoaPods trunk. Plugin iOS floor 15. |
910
| Flutter `tugboat` | 0.8.14 | Android `com.gettugboat.sdk:capture-runtime:0.1.0` from Maven Central. Apple `TugboatCaptureRuntime` 0.1.x compiled from monorepo sources (unpublished CocoaPod is not required). Plugin iOS floor 12; native capture still reports unsupported below iOS 15. |
1011
| Flutter `tugboat` | 0.8.13 | Android `capture-runtime` 0.1.x compiled from monorepo sources (hosted Maven is not required). Apple `TugboatCaptureRuntime` 0.1.x compiled from monorepo sources (unpublished CocoaPod is not required). Plugin iOS floor 12; native capture still reports unsupported below iOS 15. |
1112
| Flutter `tugboat` | 0.8.12 | none (Flutter `flutterRepaintBoundary` only; session identity stamp patch) |
12-
| Flutter `tugboat` | 0.9.0 (planned) | Android `capture-runtime` 0.1.x and Apple `TugboatCaptureRuntime` 0.1.x |
1313
| Apple `TugboatCaptureRuntime` | 0.1.0 | CocoaPods trunk / SwiftPM git tag; iOS 15 live Flutter-layer CPU path |
1414
| `@tugboat/react-native` || not started |
1515

sdks/flutter/packages/tugboat/CHANGELOG.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,27 @@
1+
## 0.9.0
2+
3+
### Changed
4+
5+
- Replace `TugboatCaptureProfile` with one privacy-safe capture policy.
6+
- Use `TugboatReplayConfig.enabled` for lifecycle configuration.
7+
- Add explicit, additive capabilities for scene inventory, viewport semantic
8+
maps, capture diagnostics, and external action context.
9+
- Keep `allTextAndMedia` as the default screenshot mask when capabilities are
10+
enabled.
11+
- Make `TugboatParameterPolicy.allowAll` mode-free and remove the duplicate
12+
production-specific parameter policy.
13+
- Remove capture-profile fields from SDK health and sink session context.
14+
- Rename the controller action-window API to `setActionContext` and
15+
`clearActionContext`.
16+
17+
### Migration
18+
19+
- Replace `profile: TugboatCaptureProfile.dormant` with `enabled: false`.
20+
- Replace `profile: TugboatCaptureProfile.productionLean` with `enabled: true`.
21+
- Replace exploration mode with `enabled: true` plus only the required
22+
additive capabilities.
23+
- Remove the `profile` argument from `TugboatReplay.activate`.
24+
125
## 0.8.17
226

327
### Fixed

0 commit comments

Comments
 (0)