feat(tips): stage 5 — GC workers + fail-closed flag + capabilities + openapi

- GC: cancel_old_drafts (draft >7d -> cancelled), cancel_stuck_pending_confirmation
  (>7d), log_stuck_claiming (read-only, >15min). Draft GC hourly + lifecycle GC
  5min, spawned behind FEATURE_TIPS. Funded-but-unattached safety net is the
  7-day window + clawback incl 'cancelled'.
- config validate(): tips enabled fails closed unless a supported chain
  (btc/ltc/xmr/wow) is on AND tip_share_base is set.
- capabilities: advertise tips=true only when actually serveable.
- regenerated openapi.json (8 /tips/social/* endpoints).

Public-tips port COMPLETE (stages 1-5). Full suite green.
This commit is contained in:
jwinterm
2026-07-10 15:51:20 -04:00
parent b7e3510553
commit 5d8d5e193f
9 changed files with 1124 additions and 2 deletions
+14 -1
View File
@@ -250,7 +250,7 @@ pub fn effective_capabilities(config: &Config) -> CapabilitiesResponse {
nostr_relay: relay_advertised(config),
premium_relay: premium_advertised(config),
feed: feed_advertised(config),
tips: config.features.tips,
tips: tips_advertised(config),
},
restore: RestoreCapability {
policy: config.restore.policy.as_str().to_string(),
@@ -333,6 +333,19 @@ fn feed_advertised(config: &Config) -> bool {
config.feed.enabled && relay_advertised(config)
}
/// Whether public tips are actually serveable: the feature is on, a share-URL
/// base is configured, AND at least one supported tip chain (btc/ltc/xmr/wow)
/// is serviceable. Mirrors the chain/relay presence-downgrade — never advertise
/// tips an instance can't escrow on or build share links for. (Grin is out of
/// the tips port, so it is not a supported tip chain here.)
fn tips_advertised(config: &Config) -> bool {
config.features.tips
&& config.tip_share_base.is_some()
&& ["btc", "ltc", "xmr", "wow"]
.iter()
.any(|asset| chain_serviceable(config, asset))
}
/// Describe this instance's enabled chains and features.
#[utoipa::path(
get,