Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
Documentation for the [Tugboat Flutter SDK](https://github.com/blendto/tugboat-flutter).

These pages describe the Flutter package in this repository. The CLI,
collector, dashboard, and Atlas services have separate ownership and should be
verified in their own repositories.
collector, Context Graph (Atlas context), and wiki have separate ownership and
should be verified in their own repositories.

## Getting started

Expand All @@ -15,7 +15,7 @@ verified in their own repositories.

## Design

- [Capture and fingerprint architecture](design/capture-and-fingerprint.md) — implemented schema-v6 identity, screenshots, semantic evidence, gaps, and next steps
- [Capture and fingerprint architecture](design/capture-and-fingerprint.md) — implemented schema-v6 identity, screenshots, inferred-event evidence, gaps, and next steps

## Repository layout

Expand All @@ -28,7 +28,7 @@ verified in their own repositories.

## Current compatibility

- package version: `0.5.3`;
- package version: `0.6.0`;
- session JSON schema: `9`;
- fingerprint schema: `6`;
- minimum Dart SDK: `3.9.2`;
Expand Down
6 changes: 3 additions & 3 deletions docs/integration/production-replay-acceptance-0.4.15.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,16 @@ side-by-side scoring. Record the new session id and Blend build before scoring.
5. **Automatic false-claim rate** — timer/auth redirects after the window, and
routes with competing pointers, stay `navigationOrigin =
automatic_or_unknown`.
6. **No semantic tap for scrolls/swipes** — completed scroll/swipe produces no
6. **No inferred tap for scrolls/swipes** — completed scroll/swipe produces no
`stream: semantic` tap; one `interaction` with `gesture=scroll|swipe`.
7. **Diagnostic isolation** — enrichment selection of `stream: semantic`
7. **Diagnostic isolation** — enrichment selection of inferred events (`stream: semantic`
excludes `capture_diagnostic`.
8. **Rage-tap precision** — three no-result taps on the same origin target flag
once; three scrolls or three successful navigation taps do not.

## Soft / observational

- Semantic event count per completed gesture should drop vs 0.4.0 raw
- Inferred event count per completed gesture should drop vs 0.4.0 raw
`tap`+`tap_settled`+scroll peer inflation.
- Legacy projection remains present until collector/graph cut over; do not
delete `tap`/`tap_settled` selection until two representative Blend flows pass
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ interaction or a gesture sequence that should be coalesced before replay.
This likely explains a major part of the replay feeling erratic: the player may
be faithfully rendering an event stream that is already too noisy.

### 5. Context graph identity was missing for diagnostics
### 5. Atlas context build identity was missing for diagnostics

All 37 `capture_diagnostic` events had
`contextEnrichment.reason = missing_context_graph_build_identity`.
Expand Down Expand Up @@ -163,7 +163,7 @@ quality and completeness of the interaction evidence around those routes.
coordinates without a clear degraded visual state.
4. Add a focused runtime acceptance flow for bottom sheets and paywalls in the
Blend app, using production collection and dashboard replay inspection.
5. Ensure capture diagnostics include or can resolve context graph build
5. Ensure capture diagnostics include or can resolve Atlas context build
identity, so replay-quality diagnostics and enrichment state can be separated
cleanly.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ Screenshot readback and PNG encoding also perform UI-thread work without a stabl
- AE1. Given an app mounted with the default dormant profile, when `activate()` is called, capture begins without rebuilding `MaterialApp`, and exactly one emitted session is linked to the activation request.
- AE2. Given activate-deactivate-activate calls in rapid succession, each created session ends once, no event is delivered to the prior session's sinks, and the second activation has a new capture-session ID.
- AE3. Given a process restart with unacknowledged outbox entries, delivery resumes within retry bounds and acknowledged envelopes are not delivered again.
- AE4. Given screenshot encoding exceeds budget, interaction events continue, screenshots are coalesced or skipped, and health reports the specific degradation without including pixels or labels.
- AE4. Given screenshot encoding exceeds budget, inferred events continue, screenshots are coalesced or skipped, and health reports the specific degradation without including pixels or labels.
- AE5. Given the same tagged actionable control in two locale variants of one exact release build, structural identity remains stable; a different build is not automatically treated as equivalent.

### Scope Boundaries
Expand Down Expand Up @@ -237,7 +237,7 @@ Release-build validation and documentation close the rollout after the behavior
- **Requirements:** R9-R10; KTD7.
- **Dependencies:** U1.
- **Files:** Modify screenshot/frame capture and replay policy files; add benchmarks and tests under `packages/tugboat/test/replay/` and `packages/tugboat/benchmark/`.
- **Approach:** Instrument capture stages, maintain a rolling budget, and coalesce or skip eligible screenshots while keeping interaction events and diagnostics.
- **Approach:** Instrument capture stages, maintain a rolling budget, and coalesce or skip eligible screenshots while keeping inferred events and diagnostics.
- **Test scenarios:** Stage timings and sizes are recorded without pixels; unchanged frames still deduplicate; overload coalesces pending captures; critical lifecycle captures follow policy; structural evidence continues when screenshots degrade; recovery clears degraded state after the budget window.
- **Verification:** Benchmark fixtures establish thresholds and tests prove predictable degradation without event loss.

Expand Down
21 changes: 17 additions & 4 deletions docs/plans/2026-07-28-001-sdk-interaction-consolidation-plan.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ inflates insight calculations such as rage taps.
configuration.

4. **Canonical `interaction` envelope with compatibility projection.** Add a
canonical semantic event shape (`type: interaction`, `gesture: tap|swipe|
canonical inferred event shape (`type: interaction`, `gesture: tap|swipe|
scroll|cancelled`) and project legacy `tap`/`tap_settled` only behind a
temporary compatibility gate. The collector and graph should migrate to the
canonical shape before the legacy pair is removed. This avoids a breaking
Expand Down Expand Up @@ -267,7 +267,7 @@ the transaction window has ended or a guard failed.
- Place the semantic-publication gate immediately before `_addEvent`. The
capture sink hub, outbox sink, and collector HTTP sink each serialize or
queue events immediately, so none can safely be made responsible for
consolidation. Enforce one terminal semantic event per transaction ID before
consolidation. Enforce one terminal inferred event per transaction ID before
it reaches any sink.
- Move `_recordCaptureDiagnostic` to the diagnostic stream and define a compact
end-of-session health aggregate for production observability.
Expand All @@ -280,7 +280,7 @@ the transaction window has ended or a guard failed.
- Serialization round-trip preserves immutable origin and successor result.
- Outbox recovery never duplicates a finalized interaction or loses its
evidence IDs.
- Normal semantic event selection excludes diagnostics and legacy projections.
- Normal inferred event selection excludes diagnostics and legacy projections.
- A session with 10 gestures publishes 10 canonical semantic interactions,
regardless of raw pointer/route/scroll callback count.

Expand Down Expand Up @@ -330,6 +330,19 @@ the transaction window has ended or a guard failed.
selection only after all acceptance gates pass for two representative Blend
flows and no consumer still relies on it.

### Migration status — 2026-08-06

- The canonical `interaction` schema and temporary compatibility projection are
implemented.
- New recordings now default to `canonicalOnly`; `dualWrite` and `legacyOnly`
require an explicit override and are deprecated for new integrations.
- Collectors and replay readers must continue accepting historical legacy rows,
but enrichment, insight, and flow-attribution paths must select canonical
semantic `interaction` records.
- Final emitter deletion is intentionally deferred. Track it through
`TODO(tugboat-legacy-projection-removal)` and the removal checklist in
`packages/tugboat/README.md`.

## Performance and safety budget

- Maximum pending transactions: one per active pointer plus a small bounded
Expand Down Expand Up @@ -380,7 +393,7 @@ the transaction window has ended or a guard failed.
analysis/formatting.
2. Build Blend against the local SDK and manually exercise the acceptance flow.
3. Query ClickHouse by SDK version and canonical interaction schema version.
4. Score origin correctness, delayed attribution, false claims, semantic event
4. Score origin correctness, delayed attribution, false claims, inferred event
count per completed gesture, diagnostic-stream isolation, and rage-tap
precision.
5. Publish a side-by-side report against a locked 0.4.0+ baseline before
Expand Down
49 changes: 49 additions & 0 deletions packages/tugboat/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,52 @@
## 0.6.0

### Changed

- **Canonical interactions are now the recording default** —
`TugboatReplayConfig.interactionPublishMode` defaults to `canonicalOnly`, so
each finalized gesture emits one semantic `interaction` instead of also
emitting `tap`, `tap_settled`, or `swipe` compatibility rows.
- **Legacy gesture publication is deprecated** — `dualWrite` and `legacyOnly`
remain explicit migration overrides for historical consumers. New
integrations must not enable them; removal prerequisites and the searchable
`TODO(tugboat-legacy-projection-removal)` marker are documented in the SDK
README.

### Added

- **Provider-neutral coded-event hook** — `TugboatReplay.eventHook` records one
logical `external_event` on the evidence stream with a bounded parameter
policy (`namesOnly`, `allowList`, `transform`, or exploration-only
`allowAll`). Values are deep-copied at hook time; dormant/disabled calls are
safe no-ops.
- **Generic network observation** — `TugboatReplay.beginNetworkCall` exposes an
exactly-once token for method, safe route template, status, outcome, and
duration. No headers, queries, bodies, raw errors, or stack traces are
retained.
- **Evidence isolation** — external and network evidence stamp session identity
only and never inherit active exploration `actionId`, `relatedEventId`, or
target/state anchors.
- **Evidence health counters** — `TugboatSdkHealth.evidence` exposes bounded
accepted/dropped/duplicate-finish counts without retaining rejected raw
values.
- **`tugboat_dio` companion package** — Dio interceptor that maps request
lifecycle callbacks onto the core network token without importing Dio into
core.

### Fixed

- **Session-bound evidence completion** — in-flight network tokens can no
longer finish into a replacement session, and session end fences reentrant
evidence before publishing its terminal event.
- **Production parameter policy** — exploration-only `allowAll` is downgraded
to names-only outside exploration, and unsupported values contribute one
drop to bounded diagnostics.
- **Session-end admission** — session end claims its in-flight future before
sync sink work, so evidence fencing no longer needs a separate ending bool.
- **Deactivate evidence fence** — `TugboatReplay.deactivate` closes evidence
admission immediately; the activation gate still owns `session_end` on
teardown.

## 0.5.3

### Added
Expand Down
Loading
Loading