feat(ingestion): GREEN — author-owned post ingestion, enablers + consumers master
Task 5a green gate. All 25 reds pass; the only remaining failure is cmd/contract-manifest, which is EXPECTED and is task 5b's work (the three new collections need //coves:ingestion-contract markers in tests/e2e). A. Migration 036 enablers deleted_accounts(did PK, deleted_at NOT NULL, deleted_rev nullable). userRepo.Delete writes the marker as step 0 of the SAME transaction, so a rolled-back deletion cannot leave a marker naming a live account. userRepo.Create clears it (now transactional) — the marker's exit is re-registration, and both service paths funnel through that insert. postgres.DeletedAccountRepository reads it; a query failure is an error, never a false. B. post.getStatus Lexicon getStatus.json (query; description records why it is deliberately unauthenticated). posts.statusService over the admissions repo; decision fields gated on rejected/removed so a pending post never carries a code. Handler omits absent optionals entirely rather than emitting null. Route registered with NO auth middleware via a new variadic RegisterPostRoutes option, keeping every existing caller compiling. C. postv2 consumer (authorpost.go) author = event.Did, enforced by a record type that HAS no author field. Erasure gate runs before anything touches the database. Community immutability discards the whole update event; unknown community stays transient; unknown author indexes anyway with bounded, non-fatal opportunistic hydration (5s, verified handles only). UpsertPending follows the gated content write, so a refused event never moves evaluated_cid backwards. Delete tombstones. D. acceptance/removal consumer + §5.4 direct fetch Repo DID must be an indexed community (transient if not — the profile event can genuinely arrive second). Tuple CAS applied through the task-2 repo; every skip returns nil. Pre-emptive removal creates its row. Acceptance-before-post converges by DirectPostFetcher: DID-resolved PDS, SSRF-guarded client, 1 MiB cap detected rather than truncated, pinned-CID verification, and a PERMANENT refusal when the fetched record names another community. That last check is also enforced on the already- indexed path, or it would be bypassable by posting before accepting. Acceptance deletions resolve their subject through acceptance_rkey; removal deletions are no-ops because their paired put outranks them. E. consumerWantedCollections ConsumerPosts keeps social.coves.community.post and gains postv2, acceptance and removal. Production wiring passes the admissions repo, the erasure lookup and the fetcher; the SSRF-relaxed fetcher constructor is named for what it does and reachable only under IS_DEV_ENV. Shared refactor, behaviour-preserving: the rev gate + content UPDATE and the gated insert are now one implementation each (applyPostContentUpdate, indexPostIfRevWins), used by both the community-repo and author-repo paths, which differ in who may claim what — not in how an edit is applied. BridgeTrust re-keyed to the AUTHOR's PDS on the postv2 path, default-deny for an unhydrated author. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>