Skip to content
Merged
2 changes: 1 addition & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ verified in their own repositories.

## Current compatibility

- package version: `0.4.15`;
- package version: `0.4.17`;
- session JSON schema: `8`;
- fingerprint schema: `6`;
- minimum Dart SDK: `3.9.2`;
Expand Down
38 changes: 36 additions & 2 deletions docs/design/capture-and-fingerprint.md
Original file line number Diff line number Diff line change
Expand Up @@ -235,9 +235,43 @@ Developer-authored identity strings can still be emitted:
- widget type names or configured `widgetNames` replacements;
- canonical structural paths.

Interaction events may also carry a `controlValue` payload (schema version 4) for
valued controls (checkbox, switch, radio, slider, dropdown / menu item, chip)
and for hit targets that expose Flutter semantic annotations:

- bools and numbers are emitted literally;
- enums and developer identifiers are emitted literally;
- arbitrary strings, including numeric strings and single-word values, are
emitted literally;
- explicit custom-control values can be supplied with
`TugboatControlValueScope`, including a stable `controlKey`, optional unit,
and numeric `min`, `max`, and `step` metadata.

`tap` includes a `controlValue` snapshot sampled at pointer-down.
`tap_settled` uses the distinct `controlValueTransition` contract with
`before` / `after` snapshots. Its post-callback sample stays bound to the
original hit element, so later taps, route changes, or dismissed overlays
cannot donate unrelated control state. Slider drags that become `swipe` events
carry a `controlValue` snapshot sampled at pointer-up.

When a typed widget value is unavailable (custom GestureDetector rows, bottom
sheets, etc.), the SDK still samples `SemanticsProperties` / live semantics
nodes under the pointer and records raw `semanticValue` / `semanticLabel`.
Standard controls may include both widget
state and semantic annotations under `sources: ["semantics","widget"]`.

Independently, every interaction event (`tap`, `tap_settled`, `swipe`,
`scroll_start`, `scroll_end`) may carry a top-level `semanticAnnotation`
payload (schema version 2) whenever Flutter semantics expose an identifier, label, value, or
selection flag on the target. This covers ordinary buttons and scrollables as
well as valued controls. The field is named `semanticAnnotation` to avoid
colliding with `tap_settled.data.settleObservation.semantic` (state-signature
change evidence).

Bounds, pointer coordinates, scroll metrics, and masked screenshot pixels are
also capture data. Apps must treat tags, route names, and subview labels as
telemetry and avoid putting user data in them.
also capture data. Apps must treat tags, route names, subview labels, and
semantic value/label tokens as telemetry and avoid putting raw user PII in
them.

## Screenshot pipeline

Expand Down
31 changes: 31 additions & 0 deletions packages/tugboat/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,34 @@
## 0.4.17

### Changed

- **Raw control and semantic values** — control values, semantic values, and
semantic labels are now sent verbatim instead of being tokenized. This makes
slider positions, durations, and template identifiers available for session
summaries and aggregate analysis.
- **Explicit custom-control values** — `TugboatControlValueScope` exposes a
stable `controlKey`, typed number/duration/enum value, optional unit, and
numeric range metadata for controls whose value is not readable from a
standard Flutter widget.

## 0.4.16

### Added

- **Privacy-safe interaction metadata** — valued controls and semantic
annotations can enrich tap, settle, swipe, and scroll events without
retaining arbitrary semantic text.

### Changed

- **Causal control-value transitions** — settled control values are captured
from the original interaction target and use a distinct transition payload.
- **Canonical interaction parity** — canonical-only tap and swipe results retain
their post-interaction control and semantic metadata without relying on
legacy projection events.
- **Cross-SDK semantics flags** — checked-state capture compiles on the
package's declared Flutter 3.35 minimum and newer enum-based SDKs.

## 0.4.15

### Added
Expand Down
44 changes: 35 additions & 9 deletions packages/tugboat/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ checkpoints around meaningful interactions, compact structural anchors, route
transitions, scrolling evidence, and optional viewport semantic maps. Capture
can be sent to the local exploration WebSocket, the HTTP collector, or both.

The current package version is `0.4.15`. Session JSON uses schema version `8`
The current package version is `0.4.17`. Session JSON uses schema version `8`
(readers still accept `6`), and structural fingerprints use fingerprint schema
version `6`.

Expand Down Expand Up @@ -209,10 +209,11 @@ Available mask levels are `explicitOnly`, `allTextAndMedia`, `allText`,
stay visible; other custom-painted or decorated image surfaces are not
classified by this mode, so wrap them in `TugboatSensitive` when needed).

The structural telemetry does not retain arbitrary `Text`, accessibility,
tooltip, or icon label strings. Dynamic list discriminators are hashed before
they enter canonical paths. Telemetry does include developer-authored routing
and identity strings where applicable:
Control values and semantic strings are retained verbatim so session summaries
and aggregate analysis can use values such as slider positions, video duration,
and selected templates. Dynamic list discriminators remain hashed before they
enter canonical paths. Telemetry also includes developer-authored routing and
identity strings where applicable:

- route names in `route_change.data` and anchor `routeKey` fields;
- `TugboatSubView.label` in state/scroll context;
Expand All @@ -222,10 +223,35 @@ and identity strings where applicable:
- normalized bounds, pointer coordinates, scroll metrics, and screenshot
pixels after the configured masking policy is applied.

Screenshots are the only captured surface that can contain rendered user
content. Choose an explicit production masking policy and test custom widgets,
platform views, and overlays in the target app before enabling production
capture.
Screenshots and telemetry can contain rendered or semantic user content. Choose
an explicit production masking policy and test custom widgets, platform views,
overlays, and semantic labels before enabling production capture.

### Explicit custom-control values

Standard Flutter controls expose their typed state automatically. Wrap custom
controls when the app knows a more useful stable key, unit, or range:

```dart
TugboatControlValueScope(
controlKey: 'video_duration',
role: 'slider',
unit: 'milliseconds',
min: 1_000,
max: 60_000,
step: 1_000,
value: TugboatVisibleControlValue.duration(
const Duration(seconds: 15),
),
child: MyDurationSlider(),
)
```

For template or preset selection, use a stable enum identifier:

```dart
value: TugboatVisibleControlValue.enumId('modern_minimal'),
```

## Event and frame model

Expand Down
Loading
Loading