Skip to content

release: v1.9.0#211

Merged
TemujinCalidius merged 4 commits into
mainfrom
dev
Jul 6, 2026
Merged

release: v1.9.0#211
TemujinCalidius merged 4 commits into
mainfrom
dev

Conversation

@TemujinCalidius

Copy link
Copy Markdown
Owner

Release v1.9.0 — dev → main (merge commit, per the branch model).

Highlights

Schema (operators — read this)

Additive only, but use npm run update (not bare db push): it applies the manual migrations in order, and #195's migration includes a backfill that plain db push skips — without it, pre-1.9.0 scheduled posts would be re-crossposted once. Migrations: 2026-07-03-post-delivery-markers.sql, 2026-07-06-fedipost-edited-at.sql.

Ops note

If you ever deployed the short-lived dev fedihome-scheduler PM2 process: pm2 delete fedihome-scheduler && pm2 save before updating.

Full notes: the ## 1.9.0 (2026-07-06) section of CHANGELOG.md.

TemujinCalidius and others added 4 commits July 3, 2026 15:00
…) (#203)

A crash between the atomic publish claim and delivery left a scheduled
post published-but-unfederated forever (no marker, no retry). Also: the
scheduler's publish path never persisted blueskyUri, so scheduled posts
never got Bluesky reply-syncing.

- Post.federatedAt records a completed delivery attempt; Post.threadsPostId
  + blueskyUri are persisted by the shared publisher (reply-sync + retry
  idempotency markers).
- Retry sweep: published scheduled posts with no completed delivery get ONE
  retry after a 10-minute QUIET period anchored to updatedAt (the claim
  bumps it) — anchoring to scheduledFor would make a post claimed late
  (downtime over its slot) retry-eligible instantly, the exact scenario
  adversarial review reproduced as a double-post.
- Double-post defenses (adversarially verified, reproduced race fixed):
  publishPost re-reads the crosspost markers just before posting (stale
  snapshot guard), publish ticks never overlap in-process (in-flight
  guard), the retry claim is an atomic federatedAt compare-and-swap, and
  AP redelivery reuses the same activity id (remote dedupe).
- Migration backfills federatedAt for scheduler-published posts predating
  the markers (they'd otherwise re-crosspost once) — db push alone is NOT
  sufficient this time; npm run update applies the SQL first (CHANGELOG
  says so explicitly).
- Tests: 313 total. Hermetic publish-post tests (the old ones hit a live
  localhost Postgres via the unmocked db import — caught in review),
  pinned claim WHERE clauses, pinned deliver-before-mark ordering,
  marker re-read + fallback, tick-overlap guard.

Closes #195

Co-authored-by: Samuel Lison <samuel@slcolonies.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ice) (#204)

The scheduler's cadences/toggles were env-only (SCHEDULER_*, read at boot).
First slice of the in-app admin/config panel (#59):

- scheduler-config: getEffectiveSchedulerConfig() overlays admin-saved
  SiteSetting overrides (scheduler.* keys) on the env defaults; 60s cache,
  invalidated on save; DB-down falls back to env (uncached). Intervals
  clamped to 10s-24h so a typo can't wedge the scheduler. No schema change
  (SiteSetting already exists).
- scheduler: one self-scheduling master loop (15s) dispatches jobs by
  elapsed-vs-configured cadence, re-reading the effective config each tick
  — toggles AND cadence changes apply within a minute, no restart. Loop is
  serialized by construction; runPublishTick keeps its in-flight guard
  (flag now claimed synchronously — an await before it opened a suspension
  window two callers could pass, caught by the overlap test).
- /api/admin/settings (GET/POST): owner-cookie only (verifyOrigin +
  await verifyAdmin, no bearer path — an app token must not reconfigure
  the instance, same stance as /admin/apps). Key allowlist, validate-all-
  before-write-any, null value deletes the override (revert to env).
- /admin/settings UI: Scheduler card (toggles + cadence inputs + "Use env
  defaults"), linked from the timeline header.

Tests: 325 total (12 new: overrides/clamp/cache/fallback, route gates +
allowlist + upsert/delete + cache invalidation, live-toggle + live-cadence
+ overlap-guard scheduler tests). Smoke-tested on a built server: page
login-gated, API 401/403 unauthenticated, scheduler boots + logs.

Co-authored-by: Samuel Lison <samuel@slcolonies.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… dropped (#205) (#208)

The inbox switch had no Update branch, so edits made on the origin
instance (Mastodon sends Update(Note|Article)) fell to default and were
silently ignored — the stored copy kept pre-edit text forever.

- New handleUpdateNote: matches the stored FediPost by the object's apId,
  re-derives content exactly like Create ingest (escaped Article title +
  sanitizeHtml + processAttachments), stamps FediPost.editedAt (new
  nullable column + manual migration), and keeps FediInteraction reply
  rows (the bell/thread copy — the ONLY copy for non-followed repliers)
  in sync. Unknown objects are ignored (no create-from-Update, matching
  Mastodon).
- Ownership gate: the transport check binds the signature to the actor's
  HOST, not the actor — the handler additionally requires the Update's
  actor to BE the stored author, closing a same-host rewrite of another
  actor's cached post. (The residual same-host limitation is transport-
  wide and pre-existing; tracked separately.)
- editedAt is clamped to <= now (remote-controlled value) and flows
  through the feed/conversation payloads automatically (full-row spread).
- Tests: 9 new (first inbox route tests) — edit applied + sanitized on
  BOTH storage paths (script/onerror payloads pinned), Article title
  escaping, wrong-actor rejection, unknown-object ignore, future-date
  clamp, non-Note/Article ignore. Adversarially reviewed: the handler's
  own authz/sanitization held; findings were pre-existing transport
  context + the two polish items applied here.

Closes #205

Co-authored-by: Samuel Lison <samuel@slcolonies.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
prepare-release.mjs minor: CHANGELOG '## Unreleased' → '## 1.9.0 (2026-07-06)', package.json + lock bumped.

Co-authored-by: Samuel Lison <samuel@slcolonies.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@TemujinCalidius
TemujinCalidius merged commit da30354 into main Jul 6, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant