Files
agent-radar 2ed3415fb7
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
2026-09-01 20:17:27 +08:00

61 lines
3.2 KiB
Markdown

# Activity Replication
`github.com/tutti-os/tutti/packages/agent/activity-replication` is the official
versioned JSON contract for uploading canonical agent activity snapshots to a
cloud projection.
The root package defines the wire batch, mutation, typed entity key, scopes,
five projection snapshots, validation, and acknowledgement/rejection
semantics. Canonical activity vocabulary comes from
`store-sqlite/canonical`; this module does not define a second set of turn or
interaction lifecycle values.
The `conformance` subpackage exposes backend-neutral fixtures through two
interfaces that match the direction of data flow:
- `ProjectionBuilder` seeds canonical state and builds the official mutations;
the Tutti SQLite adapter and tsh local builder run `ProjectionFixtures`.
- `Sink` applies official mutations and reads the final projection; tsh-server
MySQL runs `SinkFixtures`.
The sink fixtures verify that:
- an already committed mutation retried after its HTTP response was lost is
accepted as a duplicate and returns its original cursor;
- a stale snapshot is an acknowledged no-op and does not block later ordered
mutations;
- reusing a mutation ID for a different identity is a permanent rejection;
- schema rejection reports the failing mutation and transaction IDs.
The contract owns no database queries, room authorization, transport,
WebSocket behavior, or GUI-derived state. `runtimeOperation`,
`runtimeOperationEvent`, and `submitClaim` are retained only as entity names
for decoding tombstone deletes; new upserts are invalid.
`Turn.identityAnchorTurnId` is an optional, provider-neutral identity relation.
When present, the Turn inherits the ultimate external identity of another Turn
in the same canonical Session; absence means the Turn owns its identity. The
anchor is immutable, non-self-referential, and flattened to one hop by the
canonical store. It does not change lifecycle, cancellation, interaction,
provider-Turn binding, or message ownership. Cloud sinks must treat an omitted
field as “not asserted” and must not clear an anchor already stored by a newer
owner. This keeps old owners readable while limiting the new behavior to owners
that actually emit the relation.
The production module depends only on the nested, dependency-free
`store-sqlite/canonical` module. The SQLite conformance adapter lives in the
store module's tests, so importing this contract does not add the SQLite driver
or daemon to a consumer's module graph.
Consumers should validate an ordered batch with `ValidateBatch`, preserve the
original durable cursor for duplicate acknowledgements, count duplicate and
stale mutations in `acceptedCount`, and use `SummarizeAcknowledgements` to
produce the batch result. `ProjectionEpoch` is an explicit rebaseline fence:
when a cloud projection is destructively reset, its paired consumer release
must increment the epoch. Clients then treat acknowledgement rows from an
older epoch as untrusted and replay the canonical projection in dependency
order before relying on cloud-derived features. The cloud sink must be deployed
before clients that emit the new field; it rejects a different epoch rather
than applying a partially compatible projection. This is an intentional
fail-closed release fence, not a compatibility mode.