Effort: thorough
atproto/prototypes/post_debate_round.py proves SciDEX can sign
and post structured records to a self-hosted PDS, and
atproto/lexicons/ already defines six SciDEX-specific record
types (debate.round, hypothesis.score, market.position,
governance.decision, review.structured, annotation.claim). What's
missing is the auto-publish loop: when a hypothesis crosses a
quality threshold, when a market closes with high consensus, when a
debate round produces a striking finding — none of those reach the
outside world today. Build the pipeline that publishes selected
events to Bluesky's public network so AT-Proto-native readers see
SciDEX's strongest output natively, with deep-links back into
scidex.ai.
migrations/<date>_atproto_publish_queue.sql:CREATE TABLE atproto_publishes (
id UUID PRIMARY KEY,
artifact_id TEXT REFERENCES artifacts(id),
record_kind TEXT NOT NULL,
target_pds TEXT NOT NULL DEFAULT
'https://pds.scidex.ai',
agent_did TEXT NOT NULL,
at_uri TEXT,
record_cid TEXT,
published_at TIMESTAMP,
also_post_to_bsky BOOLEAN NOT NULL DEFAULT FALSE,
bsky_post_uri TEXT,
status TEXT NOT NULL DEFAULT 'pending' CHECK
(status IN ('pending','published','failed','skipped')),
last_error TEXT,
created_at TIMESTAMP NOT NULL DEFAULT NOW()
);scidex/atlas/atproto_publisher.py:ai.scidex.hypothesis.score record; if score crossing 0.9,also_post_to_bsky=TRUE (a app.bsky.feed.postai.scidex.market.position.qualityScore >= 0.85 → publishai.scidex.debate.round.LISTEN/NOTIFY from update triggershypotheses, markets, debate_rounds.
scripts/atproto_publish_worker.py:SKIP LOCKED (orpds/setup_agents.shapp.bsky.feed.post lexicon.
scidex/atlas/atproto_publisher.py:PERSONA_DID_MAP.
/senate/atproto-publishes listsquality_gate.py:enforce_factuality_gate so we don't pushtests/test_atproto_publisher.py: stubbed PDSpds.scidex.ai; capture the at_uri in thepost_debate_round.py prototype.
atproto Python SDK already imported inprototypes/post_debate_round.py.atproto/lexicons/* — record schemas (exist).atproto/pds/setup_agents.sh — persona DIDs (exist).q-perf-deferred-work-queue — alternate worker substrate.q-integ-hypothesis-is-annotations — also pushes to AT Proto.atproto/lexicons/ (6 record types), atproto/prototypes/post_debate_round.py (prototype), atproto/pds/setup_agents.sh (DIDs) all exist on mainscidex/atlas/atproto_publisher.py does NOT exist — need to createscripts/atproto_publish_worker.py does NOT exist — need to createtests/test_atproto_publisher.py does NOT exist — need to createatproto_publishes table does NOT exist — need migrationenforce_factuality_gate not found in codebase — will implement placeholder that checks for retracted paper citationsmigrations/20260427_atproto_publish_queue.sql (atproto_publishes,scidex/atlas/atproto_publisher.py: PERSONA_DID_MAP, trigger handlers (hypothesis/market/debate),scripts/atproto_publish_worker.py: SKIP LOCKED batch daemon, PDS client per persona,/senate/atproto-publishes: operator console with stats, recent publishes, failures + retry, draft previewtests/test_atproto_publisher.py: DID map, enqueue idempotency, rate limit, record builders,fa3dd2c3f from a previous attempt but tests were failingh-test-001) that don't exist in DB, causing FK violationstests/test_atproto_publisher.py:h-test-* artifact IDs with real wiki- artifacts (wiki-parkinsons, wiki-AL002, etc.)test_atproto_publishes_page_loads_with_stats: no at:// links in empty state → assert "at://" not in htmltest_atproto_publishes_page_shows_recent_rows: h-test-001/mkt-001 → wiki-parkinsons/wiki-AL002test_handle_hypothesis_score_change_enqueues: replaced broken inline mock with proper mock DB via get_pg_connection patchh-batch-* → wiki-VG-3927h-retry-001/h-skip-001 → wiki-VG-3927/wiki-VHB937
pytest tests/test_atproto_publisher.py -v → 28 passed)origin/main cleanly (no conflicts)