Skip to content

th-19cca5: th pearls sync — two-way sync with Smoo Projects work items - #529

Open
brentrager wants to merge 3 commits into
mainfrom
th-19cca5-pearls-sync
Open

brentrager wants to merge 3 commits into
mainfrom
th-19cca5-pearls-sync

Conversation

@brentrager

@brentrager brentrager commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Problem

Pearls moved to a machine-local SQLite file (#522, th-d3e842) and lost Dolt's push/pull. The Smoo Projects work-items API (smoo work, 09766e3) is the shared home now; smooth-diver's direct Jira client is the wrong seam once smoo work jira import exists.

Solution

th pearls sync [--project <KEY|uuid>] [--pull-only|--push-only] [--dry-run] [--json] [--org] — one explicit, offline-first reconcile verb (crates/smooth-cli/src/pearls_sync.rs).

  • Identity: new sync_map table in pearls.db (pearl_id ↔ remote_id + per-side updated_at baselines). Pushed items carry externalRef = th-xxxxxx@<checkout-dir>; a fresh machine adopts by ref (and keeps the pearl id when free) instead of duplicating. Project binding lives in the store's per-project config (sync.project_id / sync.project_key); sync.last_pull_at is the updatedSince cursor.
  • Field map: title/description/labels/parent; status closeddone, deferredblocked (in_review/cancelled fold in on pull and are never demoted on push); priority inverted (pearl P0 ↔ work item 4); epic survives as a label; deps → blocks links on the blocker; comments both ways with a pearl-comment:<id> first line to stop echoes.
  • Conflicts: "changed" = differs from the last-sync baseline (clock skew between laptop and server must not hide an edit), timestamps only break ties, newer wins, the loser is listed under conflict: — never silent. Create-on-first-sight both ways. Nothing is ever deleted on either side; orphans are reported under skipped:.
  • th pearls push/pull notices now point at th pearls sync. smooth-diver is left in place; docs mark th jira sync legacy.

Depends on the smooai side (SmooAI/smooai PR for SMOODEV-3128: labels, external_ref, externalRef/label/updatedSince list filters). Against today's prod API a sync still works but can't adopt by ref (no externalRef yet) and pulls full pages instead of incrementally.

Verification

  • cargo fmt --check, cargo clippy (no new hits in touched files), cargo test -p smooai-smooth-cli -p smooai-smooth-pearls → 796 + 203 pass, pnpm format:check.
  • Tests: mapping round-trips (status/priority/type/labels/external ref/comment marker), and an in-process axum mock of the work-items API covering pull-create (+deps +comments, echo filtered), push-create (externalRef, blocks link, marked comment), updates both ways, conflict logged + newer wins, adoption by externalRef, free-id reuse, dry-run writes nothing, push-only reports remote-newer, delete-safety (DELETE routes assert 0 calls).
  • Smoke against real api.smoo.ai (read-only): th pearls sync --project SMOODEV --dry-run --json from the smooth checkout → would create 3027 local pearls (the Jira-imported SMOODEV items) and push 1541 pearls; 0 conflicts; ~10s. A real first run should target a dedicated Smoo project per repo (e.g. key SMOOTH), not SMOODEV.

Landing

Rebased onto main after #522 landed; auto-merge armed. Checkpoints (th-9483e8, smooth-checkpoint: comments) ride along through comment sync. Pearl th-19cca5.

🤖 Generated with Claude Code

https://claude.ai/code/session_01M9HmiTg9pYARWUdaXYasqq

@changeset-bot

changeset-bot Bot commented Sep 8, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: d149ec2

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@smooai/smooth Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@brentrager
brentrager force-pushed the th-19cca5-pearls-sync branch from 3e8081c to 438eb30 Compare September 8, 2026 16:27
@brentrager
brentrager changed the base branch from th-d3e842-pearls-sqlite to main September 8, 2026 16:27
@brentrager
brentrager enabled auto-merge (squash) September 8, 2026 16:27
Pearls moved to a local SQLite file (th-d3e842) and lost Dolt push/pull.
The platform's work-items API is the shared home now, so this adds one
explicit reconcile verb instead of a second replication system:

- `th pearls sync --project <KEY>` binds a checkout (stored in the store's
  config table), then `th pearls sync [--pull-only|--push-only] [--dry-run]
  [--json]` pulls, pushes, and reconciles deps (blocks links) + comments.
- New `sync_map` table (pearl_id ↔ remote_id + per-side updated_at
  baselines). Pushed items carry `externalRef = th-xxxxxx@<checkout-dir>`
  so other machines adopt instead of duplicate.
- Field map: status closed↔done / deferred↔blocked (remote in_review /
  cancelled never demoted), priority inverted (P0 ↔ 4), epic survives as a
  label, comments carry a `pearl-comment:<id>` marker to stop echoes.
- "Changed" = differs from the last-sync baseline (laptop/server clock skew
  must not hide an edit); timestamps only break ties; conflicts are listed,
  never silent. Nothing is ever deleted on either side.
- push/pull notices now point at `th pearls sync`; smooth-diver's Jira
  client stays (docs mark it legacy — `smoo work jira import` + sync).

Tests: mapping round-trips, an in-process axum mock of the work-items API
covering pull-create, push-create, updates both ways, conflict, adoption by
external ref, dry-run, push-only, and delete-safety.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M9HmiTg9pYARWUdaXYasqq
@brentrager
brentrager force-pushed the th-19cca5-pearls-sync branch from 438eb30 to ea7ccb3 Compare September 9, 2026 13:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant