---
phase: quick
plan: 260325-fij
type: execute
wave: 1
depends_on: []
files_modified:
  - .claude/skills/odb-ship/SKILL.md
autonomous: true
requirements: []
must_haves:
  truths:
    - "odb-ship Phase 4 triggers seeder after clearing checkpoints and waits for all 16 symbols to have fresh Parquet"
    - "odb-ship Phase 4 clears kintsugi_log rate limit after sync_flush, restarts kintsugi, waits for yesterday-repair pass"
    - "odb-ship Phase 5 includes yesterday-to-today Stathera boundary check requiring 0 gaps"
  artifacts:
    - path: ".claude/skills/odb-ship/SKILL.md"
      provides: "Updated deploy pipeline with post-deploy health guarantee"
      contains: "seeder.*Parquet"
  key_links: []
---

<objective>
Update odb-ship SKILL.md to guarantee healthy heartbeat post-deploy by adding three new steps to the deploy pipeline.

Purpose: Current deploys leave gaps between yesterday and today at day boundaries, stale Parquet caches, and kintsugi rate-limited from repairing. This causes heartbeat false alarms for hours after deploy. These steps ensure the first heartbeat after deploy is clean.

Output: Updated SKILL.md with seeder trigger, kintsugi rate-limit clear + yesterday-repair wait, and boundary Stathera check.
</objective>

<execution_context>
@$HOME/.claude/get-shit-done/workflows/execute-plan.md
@$HOME/.claude/get-shit-done/templates/summary.md
</execution_context>

<context>
@.claude/skills/odb-ship/SKILL.md
</context>

<tasks>

<task type="auto">
  <name>Task 1: Add post-deploy health guarantee steps to odb-ship SKILL.md</name>
  <files>.claude/skills/odb-ship/SKILL.md</files>
  <action>
Make three targeted insertions into the odb-ship SKILL.md deploy pipeline:

**Insertion 1: After Phase 4.3 (Clear Stale Streaming Checkpoints), add new section "4.3b Refresh Parquet Tick Cache"**

Add a step that triggers the Binance seeder manually (not via timer) and waits for it to complete for all 16 symbols. This ensures fresh Parquet files exist before the sidecar starts (sidecar reads Parquet on startup for catchup).

```bash
# Trigger seeder for all symbols and wait for completion
ssh bigblack '~/opendeviationbar-py/.venv/bin/python3 -c "
from opendeviationbar.storage.tick_cache_seeder import TickCacheSeeder
seeder = TickCacheSeeder()
seeder.seed_all()
print(\"Seeder complete: all symbols have fresh Parquet\")
"'
```

If that's not the right API, use the systemd oneshot approach instead:

```bash
# Trigger seeder oneshot and wait for completion
ssh bigblack 'systemctl --user start opendeviationbar-seeder && echo "Seeder triggered"'
# Wait for seeder to complete (oneshot exits when done)
for i in $(seq 1 60); do
  if ssh bigblack 'systemctl --user is-active opendeviationbar-seeder 2>/dev/null' | grep -q 'inactive'; then
    echo "Seeder complete"
    break
  fi
  echo "Waiting for seeder... ($i/60)"
  sleep 5
done
```

Add a verification step to confirm Parquet files exist for today (or yesterday if just past midnight):

```bash
ssh bigblack 'ls ~/.cache/opendeviationbar/ticks/BTCUSDT/ | tail -3 && echo "---" && find ~/.cache/opendeviationbar/ticks/ -name "$(date -u +%Y-%m-%d).parquet" | wc -l'
```

Explain WHY: "Fresh Parquet ensures the sidecar's Parquet-first catchup (SEED-001) has data to work with, avoiding full REST fill which is slow and burns rate limit."

**Insertion 2: After Phase 4.6 sync_flush + Stathera check passes and kintsugi is started (around line 557), add new section "4.6c Clear Kintsugi Rate Limit and Wait for Yesterday Repair"**

After kintsugi starts, add steps to:

1. Clear the kintsugi_log table (removes rate-limit entries that prevent immediate re-repair of yesterday's gaps):

```bash
ssh bigblack 'curl -s "http://localhost:8123/" --data-binary "TRUNCATE TABLE opendeviationbar_cache.kintsugi_log" && echo "kintsugi_log cleared"'
```

1. Restart kintsugi so it picks up the cleared rate limits:

```bash
ssh bigblack 'systemctl --user restart opendeviationbar-kintsugi'
```

1. Wait for kintsugi to complete at least one yesterday-repair pass. Poll kintsugi logs for completion signal:

```bash
KINTSUGI_DONE=0
for i in $(seq 1 60); do
  if ssh bigblack 'journalctl --user -u opendeviationbar-kintsugi --since "5 min ago" --no-pager 2>/dev/null | grep -q "repair.*complete\|no.*gaps\|0 shards"'; then
    echo "Kintsugi yesterday-repair pass complete"
    KINTSUGI_DONE=1
    break
  fi
  echo "Waiting for kintsugi repair pass... ($i/60)"
  sleep 10
done
if [ "$KINTSUGI_DONE" -eq 0 ]; then
  echo "WARNING: Kintsugi repair pass did not complete within 10 min"
  echo "Check logs: ssh bigblack 'journalctl --user -u opendeviationbar-kintsugi -n 50'"
fi
```

Explain WHY: "Deploy kills sidecar, creating a gap at the day boundary. Kintsugi repairs yesterday's gaps but the kintsugi_log rate limit from the previous session blocks immediate re-repair. Clearing the log and waiting for one pass ensures yesterday is clean before verification."

**Insertion 3: In Phase 5 Verification, after quick-path check #2 (ClickHouse + Stathera gaps), add "5.2b Yesterday-to-Today Stathera Boundary Check"**

Add a cross-day-boundary Stathera check that verifies zero gaps at the yesterday/today boundary for all symbol+threshold combinations:

```bash
ssh bigblack 'curl -s "http://localhost:8123/" --data-binary "
SELECT
  symbol,
  threshold_decimal_bps,
  yesterday_last_tid,
  today_first_tid,
  today_first_tid - yesterday_last_tid - 1 AS tid_delta
FROM (
  SELECT
    symbol,
    threshold_decimal_bps,
    argMaxIf(last_agg_trade_id, close_time_us, toDate(close_time_us/1000000) = yesterday()) AS yesterday_last_tid,
    argMinIf(first_agg_trade_id, close_time_us, toDate(close_time_us/1000000) = today()) AS today_first_tid
  FROM opendeviationbar_cache.open_deviation_bars FINAL
  WHERE toDate(close_time_us/1000000) >= yesterday()
  GROUP BY symbol, threshold_decimal_bps
  HAVING yesterday_last_tid > 0 AND today_first_tid > 0
)
WHERE tid_delta != 0
FORMAT PrettyCompact"'
# Empty result = PASS (0 boundary gaps)
# Any rows = FAIL (gaps or overlaps at day boundary)
```

State the acceptance criterion: "Empty result means zero Stathera gaps at the yesterday/today boundary. Any rows indicate gaps (positive tid_delta) or overlaps (negative tid_delta) that need investigation."

Also add "Yesterday-Today Boundary" as a new row in the Phase 5 Verdict Table.

**Style notes:**

- Match the existing SKILL.md style: bash code blocks with comments, explanation paragraphs, numbered sub-steps
- Use the existing `ssh bigblack` pattern for all remote commands
- Reference existing concepts (SEED-001, Stathera, kintsugi_log, rate limit) by name
- Keep the "Lessons Learned" section reference to kintsugi_log rate-limit reset (already at line ~902) — don't duplicate it, just cross-reference
  </action>
  <verify>
  <automated>grep -c "4.3b\|Refresh Parquet\|4.6c\|Clear Kintsugi Rate Limit\|Yesterday.*Today.*Boundary\|boundary.\*Stathera\|Yesterday-Today Boundary" .claude/skills/odb-ship/SKILL.md | xargs test 4 -le</automated>
  </verify>
  <done>
  - SKILL.md has new section 4.3b that triggers seeder and waits for Parquet refresh
  - SKILL.md has new section 4.6c that clears kintsugi_log, restarts kintsugi, waits for yesterday-repair pass
  - SKILL.md Phase 5 has yesterday-to-today Stathera boundary check with 0-gap requirement
  - Phase 5 Verdict Table has "Yesterday-Today Boundary" row
  - All new sections use existing SSH/bash patterns and reference existing concepts
    </done>

</task>

</tasks>

<verification>
- Read the updated SKILL.md and verify the three new sections are properly placed in the pipeline order
- Verify no existing sections were accidentally deleted or corrupted
- Verify the ClickHouse query syntax is correct (uses _us column names, FINAL, proper date functions)
</verification>

<success_criteria>

- odb-ship SKILL.md contains 3 new pipeline steps that guarantee post-deploy health
- Steps are correctly ordered: seeder (4.3b) before sidecar start, kintsugi clear (4.6c) after sync_flush, boundary check (5.2b) in verification
- All commands use existing patterns (ssh bigblack, curl to CH, journalctl polling)
  </success_criteria>

<output>
After completion, create `.planning/quick/260325-fij-update-odb-ship-to-guarantee-healthy-hea/260325-fij-SUMMARY.md`
</output>
