You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
4.8 KiB
4.8 KiB
PR: Structured Polling + Idempotency + CAS Watermarking (iOS/Android/Web)
Timestamp: 2025-10-07 04:32:12 UTC
What's in this PR
- Platform-agnostic generic polling interface with Zod-validated request/response
- Idempotency on poll + ack (
X-Idempotency-Key
) and unified BackoffPolicy - Watermark CAS to prevent bootstrap races; monotonic
nextAfterId
contract - Outbox pressure controls with back-pressure & eviction strategies
- Telemetry budgets (low-cardinality metrics; request-level data → logs only)
- Clock sync endpoint/logic with skew tolerance
- Minimal host-app example + stale-data UX per platform
Why
- Prevents dupes/gaps under retries, background limits, and concurrent devices
- Standardizes error handling, rate-limit backoff, and schema validation
- Tightens security (JWT claims, secret storage) and observability
Checklists
Contracts & Behavior
- Types + Zod schemas exported from
@timesafari/polling-contracts
- Canonical response/deep-link Jest snapshots
X-Idempotency-Key
required for poll + ack (400 if missing)- Unified
calculateBackoffDelay()
used on all platforms - Watermark CAS proven with race test (final =
max(jwtId)
)
Storage & Telemetry
- Outbox defaults:
maxUndelivered=1000
,backpressureThreshold=0.8
,maxRetries=3
- Gauges:
outbox_size
,outbox_backpressure_active
- Metrics low-cardinality; high-cardinality details only in logs
Security & Time
- JWT claims verified (
iss/aud/exp/iat/scope/jti
) + skew tolerance (±30s) /api/v2/time
orX-Server-Time
supported; client skew tests pass- Secrets stored via platform keystores / encrypted storage
Docs & Samples
- Minimal host-app example: config → schedule → deliver → ack → advance watermark
- Stale-data UX snippets (Android/iOS/Web)
Acceptance Criteria (MVP)
- End-to-end poll → notify → ack → advance watermark exactly once
- 429 obeys
Retry-After
; 5xx uses jittered exponential; no duplicate notifications - App/process restarts drain outbox, preserving ordering & exactly-once ack
- Background limits show stale banner; manual refresh works
- P95 poll duration < target; memory/battery budgets within limits
Testing
- Unit Tests: Comprehensive Jest test suite with snapshots
- Integration Tests: k6 fault-injection smoke test for poll+ack flow
- CI/CD: GitHub Actions with automated testing and smoke tests
- Platform Tests: Android/iOS/Web specific implementations validated
Files Changed
packages/polling-contracts/ # New contracts package
├── src/
│ ├── types.ts # Core TypeScript interfaces
│ ├── schemas.ts # Zod schemas with validation
│ ├── validation.ts # Validation utilities
│ ├── constants.ts # Canonical constants
│ ├── backoff.ts # Unified backoff policy
│ ├── outbox-pressure.ts # Storage pressure management
│ ├── telemetry.ts # Metrics with cardinality budgets
│ ├── clock-sync.ts # Clock synchronization
│ └── __tests__/ # Comprehensive test suite
├── examples/
│ ├── hello-poll.ts # Complete host-app example
│ └── stale-data-ux.ts # Platform-specific UX snippets
└── package.json # NPM package configuration
k6/poll-ack-smoke.js # k6 fault-injection test
.github/workflows/ci.yml # GitHub Actions CI/CD
doc/STARRED_PROJECTS_POLLING_IMPLEMENTATION.md # Updated implementation guide
Breaking Changes
None - this is a new feature addition that doesn't modify existing APIs.
Migration Guide
Existing implementations can gradually migrate to the new generic polling interface:
- Phase 1: Implement generic polling manager alongside existing code
- Phase 2: Migrate one polling scenario to use generic interface
- Phase 3: Gradually migrate all polling scenarios
- Phase 4: Remove old polling-specific code
Performance Impact
- Memory: Bounded outbox size prevents memory leaks
- Battery: Respects platform background execution limits
- Network: Idempotency reduces duplicate server work
- Latency: P95 < 500ms target maintained
Security Considerations
- JWT Validation: Comprehensive claim verification with clock skew tolerance
- Secret Storage: Platform-specific secure storage (Android Keystore, iOS Keychain, Web Crypto API)
- PII Protection: DID hashing in logs, encrypted storage at rest
- Idempotency: Prevents replay attacks and duplicate processing
Ready for merge ✅