CopilotKit / CopilotKit/outpost
Sync engine: echo detection can never fire, and inbound changes are silently discarded
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 7
- Forks
- 3
- Avg merge
- 7d 16h
- Merged PRs (30d)
- 15
Description
Summary
Echo detection in the bidirectional sync engine appears to be implemented but can never fire,
so a change pushed out to a tracker can be re-ingested as a new inbound change. Found during
a code review of an unrelated PR.
Findings — packages/outpost/shared/src/sync/engine.ts
1. Echo detection queries the wrong direction. Outbound pushes are recorded with
source='outpost', but shouldSync queries the reverse plugin pair, so the record it needs
is never the record it looks for. The guard is structurally unreachable rather than merely
buggy.
2. targetPlugin inside payloadHash makes cross-direction matching impossible.
Because the hash includes the target, the same logical change hashes differently in each
direction — so even a corrected query could not match.
3. The echo check runs at enqueue but the event is written at execute. Two changes
arriving inside that window both pass the check, producing duplicate TRACKER_SYNC jobs.
4. Inbound webhook changes are silently discarded while reporting success. Comment, label,
priority, assignee and close changes arriving inbound are dropped, and SyncResult still
reports success — so a sync that did nothing looks like a sync that worked.
5. computeHash's array replacer strips nested keys, so distinct changes can collide on
the same hash.
Why it matters
Sync is currently exercised lightly, which is why this has not produced a visible incident.
As soon as bidirectional Linear sync carries real traffic, the failure mode is an echo loop
between Outpost and the tracker, or silently dropped inbound edits — both hard to diagnose
from the outside because the code reports success.
Acceptance criteria
-
shouldSyncmatches the direction that pushes actually record, with a test that fails
against the current implementation -
payloadHashis direction-independent - The echo record is written atomically with (or before) the enqueue, so two rapid changes
cannot both pass - Inbound comment/label/priority/assignee/close changes are either applied or reported as
unsupported — never silently dropped withsuccess: true -
computeHashcovers nested keys
Related: #95, #111
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in packages/outpost/shared/src/sync/engine.ts, reading shouldSync, payloadHash, computeHash, enqueue/execute handling, and SyncResult. Trace how outbound records and inbound webhook changes move through these entry points, then add focused tests for direction matching, atomic echo handling, nested-key hashing, and unsupported inbound changes. Done means every acceptance criterion is covered without silent success.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- backend, distributed-systems
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100