# PRD — Backlog Provider Sync Adapters · Workstream Q > **Status:** DRAFT for ratification · **Goals:** Q1–Q3 · **Doctrine:** NS-12 (ratified D3) > **Debate pass 2026-07-09:** panel findings folded — see `DEBATE-FINDINGS.md`. ## Mission Users choose where they _see and touch_ work — Gitea, GitHub, a local kanban — while the **Mosaic Backlog on native Postgres stays the sole record and dispatch engine** (upholds ASM-1; NS-3/NS-4/NS-5 guarantees never depend on an external provider). Providers attach as bidirectional sync adapters. ## Requirements ### Adapter interface + Gitea (Q1) | ID | Requirement | | ---- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Q-R1 | A `BacklogProviderAdapter` interface: map card ⇄ external item (create/update/close/comment/label), with stable external-id linkage stored on the card. | | Q-R2 | Sync is bidirectional and conflict-safe: native record wins on divergence; external edits arrive as proposed mutations (applied if non-conflicting, else surfaced). | | Q-R3 | Claims, TTLs, depends_on DAG, and dispatch state live **only** in the native record; adapters project them (e.g. as labels/comments) but never own them. | | Q-R4 | Gitea adapter first (webhook + API), configured per workspace: repo mapping, label conventions, direction (mirror-out / mirror-in / full). | | Q-R5 | Adapter enable/disable is workspace configuration; zero adapters is a fully supported mode. | ### GitHub (Q2) | ID | Requirement | | ---- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Q-R6 | Same interface, GitHub Issues backend. Existing `packages/cli-tools` platform detection informs but does not implement this (that is dev tooling, not product runtime). | ### Local kanban (Q3) | ID | Requirement | | ---- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Q-R7 | A webUI kanban board over the native backlog (no external provider needed) — the "local kanban" choice. Builds on W3's card views and/or the existing `KanbanBoard` component upgraded from demo-grade to live data. | ## Debate-accepted deltas (2026-07-09) — normative | ID | Requirement | | ----- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Q-R8 | **External-ref linkage is one shared mechanism:** a unique-indexed `external_refs(entity_id, system, external_id)` table serves adapter linkage (Q-R1), migration idempotency (X-R4 anti-join), and re-point verification (X-R6) — built once, three consumers. Idempotent upsert; a violated unique index is a converge signal, never an overwrite. | | Q-R9 | **Crash-safe external creates:** the adapter writes a `pending-link` row **before** any external create and embeds a deterministic card-id marker in the created item, so a crash between create and link-back is recovered by scan, never by duplicate creation. | | Q-R10 | **Echo-loop guard:** both directions carry revision counters; adapter-authored external edits are tagged (marker/actor) and skipped on read-back. A sync cycle that would re-import its own write is a hard test failure. | | Q-R11 | The sync engine is a **level-triggered reconciler** over desired-vs-observed state (same doctrine as J6), not a webhook-only event chase: webhooks accelerate convergence, the reconciler guarantees it. Missed webhooks are a latency event, not a correctness event. | | Q-R12 | Card spec immutability (J-R20) projects cleanly: the mirrored issue body is the pinned spec revision; amendments append as **ordered provider comments**, never body rewrites, so external watchers see the same amendment history as the native record. | ## Acceptance criteria 1. A card created by Jarvis (J3) appears as a Gitea issue within one sync interval; closing the issue in Gitea marks the card for review, not silent closure; dispatch/claims never round-trip through Gitea. 2. Killing the adapter mid-mission: dispatch continues unaffected (record is native); on restart, sync converges without duplicates. 3. The same mission can be mirrored to Gitea and viewed on the local kanban simultaneously without state divergence. 4. **Named crash barriers** at every external-call boundary (`before_external_create`, `after_create_before_link`, `after_link_before_ack`): kill the adapter at each; zero duplicate external items, zero orphaned cards. CI rule: a new external call site without a named barrier + kill test **fails the build**. Residual randomized soak is trace-directed (§3.6 disposition). ## Non-goals - External provider AS the backlog (vetoed — "truly swappable backends" option declined 2026-07-09). - Two-way sync of claims/TTL semantics (external systems can't express them; projection only). ## Assumptions - ASSUMPTION: the delivery fleet's _engineering_ PR/issue flow on the stack repo itself continues to use `cli-tools`/Gitea directly — workstream Q is the product feature for user workspaces, not a replacement for the dev workflow.