c8a4fd5ba3
Two correctness fixes on the Phase 3 concurrent claim-based ingest path: - Slug-lock timeout / reduce failure no longer silently drops work. When a per-slug lock can't be acquired within wikiSlugLockWait, or reduce returns an error, the page's read-modify-write never lands. Previously the owning document was still counted as successful and its pending row was deleted at trim time, permanently losing the contribution (finalize only rebuilds the index / cross-links, it does not re-run reduce). Such documents are now folded into failedOps: their rows stay queued, their finalizing slot is held, and requeueFailedOps' fail_count budget retries them (dead-lettering a permanently hot/broken slug). - ClaimBatch now claims by dedup_key affinity so a document is never split across concurrent batches. limit counts distinct dedup_keys (documents), and ALL eligible rows sharing a key are claimed together. On Postgres the per-key anchor row is locked with FOR UPDATE SKIP LOCKED, handing concurrent claimers disjoint key sets. This restores in-document ordering (e.g. ingest-then-retract collapses correctly) that the per-batch dedup could not guarantee once the exclusive per-KB lock was removed, preventing a stale ingest from resurrecting a retracted document. Adds repository tests for same-key affinity and in-flight sibling rows.