Files
indiekit-server/memory/feedback_patches.md
Sven 5e50d7aceb docs: add CLAUDE.md and memory files for AP threading context
CLAUDE.md covers patch authoring rules, post-type discovery, the two
reply compose paths, ap_timeline insertion timing, fork dependencies,
and common debugging entry points.

memory/ contains three files:
- project_activitypub.md — data flows, syndicator config, all AP patches
- project_architecture.md — FreeBSD jails, MongoDB collections, actor URLs
- feedback_patches.md — patch pattern, known fragile points, threading gotchas

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-30 08:30:32 +02:00

3.0 KiB
Raw Permalink Blame History

Patch Management — Lessons Learned

Patch Script Pattern

const MARKER = "// [patch] my-patch-name";
const OLD_SNIPPET = `exact text to find`;
const NEW_SNIPPET = `replacement text ${MARKER}`;

// Check MARKER first → skip if already applied
// Check OLD_SNIPPET → warn if not found (upstream may have changed)
// Replace and write only if source changed

Use $setOnInsert for MongoDB upserts in patches that add timeline items — idempotent, safe to call multiple times (e.g. from both patch and syndicator).

Target File Candidates

Always include both paths:

const candidates = [
  "node_modules/@rmdes/indiekit-endpoint-activitypub/...",
  "node_modules/@indiekit/indiekit/node_modules/@rmdes/indiekit-endpoint-activitypub/...",
];

Known Fragile Patterns

  • Exact whitespace matters. Patch OLD_SNIPPETs must match node_modules source byte-for-byte, including indentation (spaces not tabs) and exact line endings.
  • Template literals in patches — escape backticks and ${} in patch script string literals using \`` and ${}`.
  • patch-microsub-reader-ap-dispatch is in serve only (not postinstall). Reason unknown but may relate to timing or the microsub package being rebuilt differently. Check both scripts when adding new microsub patches.

AP Threading — Two Compose Paths

Replies can come from two different UIs. Each has different syndication logic:

Path Syndication checkbox pre-checked by
AP reader (/activitypub/admin/reader/compose) target.defaultChecked set in composeController()
Microsub reader (/microsub/admin/reader/compose) target.checked from Micropub q=config response
Mastodon client API (POST /api/v1/statuses) mp-syndicate-to hardcoded to publicationUrl (always AP)

The AP reader compose form uses target.defaultChecked (NOT target.checked) in its template. If composeController() doesn't set defaultChecked correctly, the AP checkbox is unchecked even though target.checked = true from the Micropub config.

ap_timeline Insertion Timing

Own posts reach ap_timeline via TWO paths:

  1. Mastodon API (POST /api/v1/statuses): Now inserts immediately after postContent.create() via patch-ap-mastodon-reply-threading. The syndicator's later upsert is a no-op ($setOnInsert).
  2. Micropub + syndication webhook: AP syndicator inserts after Eleventy build completes (30120 s).

Always ensure new post creation paths insert to ap_timeline immediately if the post may be replied to again before the build webhook fires.

Post Type Discovery Dependency

getPostType(postTypes, properties) uses Map.has(key) — only KEY presence matters, not value.

  • "in-reply-to" present (any value, even empty) → "reply"
  • If in-reply-to is absent → falls through to "note"

If in-reply-to is silently lost (null inReplyTo in Mastodon API, unchecked form field, etc.), the post silently becomes a note with no error. Check this first when debugging "wrong post type" issues.