* fix(jira): harden _remote_links fetch — transient API failure no longer wipes parquet rows
Pre-fix, all three fetch_remote_links call sites (service.py,
scripts/backfill.py, scripts/backfill_remote_links.py) silently
returned [] on 401/403/429/5xx or httpx.RequestError. Callers overlaid
that [] onto cached issue JSON, and transform_remote_links interpreted
the empty list as 'issue legitimately has no remote links — delete
existing rows', so a transient Jira auth blip permanently wiped
remote-link history.
Now:
- Every fetch site raises JiraFetchError on non-200/non-404 status,
on httpx.RequestError, and on the 'service not configured' path.
- Overlay sites skip the _remote_links key when fetch raises, leaving
it ABSENT (not present-but-empty).
- transform_remote_links returns None for absent/null keys (preserve
existing rows) vs [] (legitimate empty — wipe).
- Both consumers (batch transform_all, incremental
transform_single_issue) honor the new contract.
- End-to-end tests
test_incremental_preserves_remote_links_when_overlay_absent and
test_incremental_wipes_remote_links_when_overlay_present_but_empty
lock both halves.
Adversarial-review fixes bundled:
- service.py: unconfigured-service path now raises JiraFetchError
instead of returning [] (a webhook can arrive while API creds are
missing — HMAC verification uses a separate JIRA_WEBHOOK_SECRET).
Regression guard test_raises_when_unconfigured added.
- consistency_check.py: AUTO_FIX_THRESHOLD bumped 10 -> 20 to cover
typical SLA-poller hiccups before escalating to ERROR.
- CLAUDE.md: connectors/jira/transform.py removed from 'Files NOT to
modify' (overlay-contract change required touching it; module
remains sensitive but is no longer off-limits).
* release: 0.54.19 — jira remote_links hardening (transient API failure no longer wipes parquet rows)
Move all Jira-specific code into a self-contained connector module:
- 22 files moved via git mv (transform, service, webhook, scripts,
systemd units, tests, docs, bin helper)
- All imports updated to use connectors.jira.* paths
- Jira is now conditional: auto-detected via JIRA_DOMAIN env var
- Webapp registers Jira blueprint only when available
- Health service monitors Jira timers only when enabled
- Profiler loads Jira tables dynamically from filesystem
- Sync settings uses config-driven dependency validation
- Renamed keboola_platform_url -> custom_url in transform
- Updated deploy.sh, sudoers-deploy, backfill_gap.sh paths
- Fixed pytest.ini to skip live tests by default