A community based topic aggregation platform built on atproto

test(posts): RED cycle 1 — the write-path flip's outer contract master

Task 6 RED. Tests, fixtures and rule-7 zero-logic stubs only; no behaviour is implemented. 25 reds, all inside the flip's blast radius. T0 (internal/core/posts, in-package) submission_rkey_test.go the deterministic postv2 rkey of PRD §4.2. Four golden TID vectors computed OUTSIDE Go (python3 transcription of the spec), each differing from the canonical one in exactly ONE input, so a derivation that drops an input reproduces the canonical value and the assertion names what went missing. Plus valid-TID parsing across seven input shapes, timestamp-inside-its-own-dedupe-bucket, call stability, set distinctness, and delimiter ambiguity. postv2_record_test.go PostV2Record's shape: no author field (decoded keys, not a substring search), required fields survive marshalling, optionals are absent rather than empty, and every lexicon surface is emitted — a field the struct lacks is a field an EDIT silently erases. T1 outer contract service_writeforward_test.go rewritten for the flipped repo. The five adjudicated outcomes: create -> author repo (and the community repo gains NO post record, asserted by listRecords over BOTH collections); delete flipped; DeleteRefusesEveryoneButTheAuthor survives with its rationale rewritten to local authorization; the unknown-community 404 dies, replaced by wrong-authority ErrNotAuthorized; the malformed table survives with its wrong-collection row respelled, and a new test proves the deprecated collection still routes to the old credential path. service_writeflip_test.go the journey: synchronous acceptance in a hosted community; a byte-identical retry returning the same URI, the same CID and NO new commit in EITHER repo; an unhosted community and an injected acceptance failure both leaving the post pending with the author's record intact; and the update journey, including the pin that an edit leaves the submission ledger completely alone. Stubs (zero-logic, no panics — reds read as failed assertions) postv2.go with PostV2Record/StrongRef/BridgedStats, SubmissionRkey, AuthorRepo + AuthorRepoFactory, SubmissionAcceptor and the two options; ErrNoAuthorCredentials + ErrConcurrentModification; UpdatePostRequest/ Response; CreatePostResponse.Status; AcceptSubmission on the engine; UpdatePost on the service. Three adjudications, flagged for review 1. CreatePost gained an explicit session parameter, matching DeletePost and the comments write path, rather than smuggling the credential through a context value a service can silently tolerate missing. This is what ripples into the handler, three mocks and six test files. 2. The seam is AuthorRepoFactory returning a narrowed AuthorRepo, mirroring this package's CommunityRepoFactory/CommunityRepo pair. The narrowing is load-bearing: the guarded put the write path needs is not on pds.Client. 3. AcceptSubmission must NOT re-run the decider — the production decider looks the post up in Postgres, and on the fast path it is not indexed yet. The fixture scripts the decider to REFUSE so a fast path that consults it fails loudly. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>