From 3ba6c2e53d291f8469a6ad4e177f43bee682a654 Mon Sep 17 00:00:00 2001 From: Sven Date: Sun, 12 Apr 2026 13:25:54 +0200 Subject: [PATCH] docs: AP patch consolidation implementation plan + spec fixes Co-Authored-By: Claude Sonnet 4.6 --- .../2026-04-12-ap-patch-consolidation.md | 486 ++++++++++++++++++ ...026-04-12-ap-patch-consolidation-design.md | 1 - 2 files changed, 486 insertions(+), 1 deletion(-) create mode 100644 docs/superpowers/plans/2026-04-12-ap-patch-consolidation.md diff --git a/docs/superpowers/plans/2026-04-12-ap-patch-consolidation.md b/docs/superpowers/plans/2026-04-12-ap-patch-consolidation.md new file mode 100644 index 00000000..27664515 --- /dev/null +++ b/docs/superpowers/plans/2026-04-12-ap-patch-consolidation.md @@ -0,0 +1,486 @@ +# AP Patch Consolidation Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Consolidate 27 individual AP patch scripts into 6 concern-based scripts, removing 2 dead patches, to make `postinstall`/`serve` maintainable. + +**Architecture:** Each consolidated script reads its target file(s) once, applies multiple patches in sequence using a shared `applyPatch()` helper, and writes once per file. Per-patch MARKER idempotency is preserved. Ordering within a script matters when one patch's output is the next patch's OLD_SNIPPET anchor (documented per script). + +**Tech Stack:** Node.js ESM (`.mjs`), `node:fs/promises` — same as existing patch scripts. No new dependencies. + +--- + +## File Map + +**Create:** +- `scripts/patch-ap-syndication.mjs` — absorbs 4 patches on `syndicator.js` +- `scripts/patch-ap-federation-infra.mjs` — absorbs 5 patches + delete-fix Change A across `federation-bridge.js`, `federation-setup.js`, `index.js` +- `scripts/patch-ap-mastodon-statuses.mjs` — absorbs 5 patches on `statuses.js` +- `scripts/patch-ap-mastodon-accounts.mjs` — absorbs 2 patches on `resolve-account.js` only (the spec header mentions `accounts.js` but both absorbed patches target `resolve-account.js`; `accounts.js` interaction patch is in misc) +- `scripts/patch-ap-mastodon-notifications.mjs` — absorbs 1 patch on `notifications.js` +- `scripts/patch-ap-mastodon-misc.mjs` — absorbs 8 patches across compose, interactions, og-image, inbox handlers + +**Modify:** +- `package.json` — replace 27 AP patch invocations with 6 consolidated ones in both `postinstall` and `serve` + +**Delete:** +- `scripts/patch-ap-syndicate-dedup.mjs` +- `scripts/patch-ap-syndicate-skip-checkin.mjs` +- `scripts/patch-ap-syndicate-skip-draft.mjs` +- `scripts/patch-ap-syndicate-skip-unlisted.mjs` +- `scripts/patch-ap-federation-bridge-base-url.mjs` +- `scripts/patch-ap-signature-host-header.mjs` +- `scripts/patch-ap-inbox-delivery-debug.mjs` +- `scripts/patch-ap-inbox-publication-url.mjs` +- `scripts/patch-ap-webfinger-before-auth.mjs` +- `scripts/patch-ap-mastodon-reply-threading.mjs` +- `scripts/patch-ap-mastodon-status-id.mjs` +- `scripts/patch-ap-mastodon-delete-fix.mjs` +- `scripts/patch-ap-status-reply-id.mjs` +- `scripts/patch-ap-interactions-context-state.mjs` +- `scripts/patch-ap-actor-cache-await.mjs` +- `scripts/patch-ap-resolve-account-timeout-safe.mjs` +- `scripts/patch-ap-notifications-status-lookup.mjs` +- `scripts/patch-ap-compose-default-checked.mjs` +- `scripts/patch-ap-og-image.mjs` +- `scripts/patch-ap-repost-announce-fix.mjs` +- `scripts/patch-ap-interactions-send-guard.mjs` +- `scripts/patch-ap-interactions-cleanup-preserve.mjs` +- `scripts/patch-ap-interactions-accounts-uid.mjs` +- `scripts/patch-inbox-ignore-view-activity.mjs` +- `scripts/patch-inbox-skip-view-activity-parse.mjs` +- `scripts/patch-ap-account-lookup-cache-fallback.mjs` (dead — upstream fixed) +- `scripts/patch-ap-skip-draft-syndication.mjs` (dead — OLD_SNIPPET no longer matches) + +--- + +## Shared Helper Pattern + +Every consolidated script uses this structure. Copy it exactly — do not vary across scripts: + +```js +import { access, readFile, writeFile } from "node:fs/promises"; + +const AP_BASE = "@rmdes/indiekit-endpoint-activitypub"; +const AP_ROOTS = [ + `node_modules/${AP_BASE}`, + `node_modules/@indiekit/indiekit/node_modules/${AP_BASE}`, +]; + +function apPath(rel) { + return AP_ROOTS.map(r => `${r}/${rel}`); +} + +async function fileExists(p) { + try { await access(p); return true; } catch { return false; } +} + +/** + * Apply a single patch to a file. + * Returns: "applied" | "already_applied" | "snippet_not_found" | "file_not_found" + */ +async function applyPatch(filePath, marker, oldSnippet, newSnippet) { + if (!(await fileExists(filePath))) return "file_not_found"; + const src = await readFile(filePath, "utf8"); + if (src.includes(marker)) return "already_applied"; + if (!src.includes(oldSnippet)) return "snippet_not_found"; + await writeFile(filePath, src.replace(oldSnippet, newSnippet), "utf8"); + return "applied"; +} + +const SCRIPT = "patch-ap-"; // change per script + +const PATCHES = [ + // { name, files: string[], marker, oldSnippet, newSnippet } + // NOTE: Order matters when one patch's newSnippet is the next patch's oldSnippet anchor +]; + +let total = 0; +for (const p of PATCHES) { + let done = false; + for (const f of p.files) { + const r = await applyPatch(f, p.marker, p.oldSnippet, p.newSnippet); + if (r === "applied") { + console.log(`[postinstall] ${SCRIPT}: applied ${p.name} to ${f}`); + total++; done = true; break; + } else if (r === "already_applied") { + console.log(`[postinstall] ${SCRIPT}: ${p.name} already applied in ${f}`); + done = true; break; + } else if (r === "snippet_not_found") { + console.warn(`[postinstall] ${SCRIPT}: ${p.name} — snippet not found in ${f}, skipping`); + } + } + if (!done) console.log(`[postinstall] ${SCRIPT}: ${p.name} — no target file found`); +} +console.log(`[postinstall] ${SCRIPT}: done (${total} patch(es) applied)`); +``` + +--- + +## Task 1: Create `patch-ap-syndication.mjs` + +**Absorbs:** `patch-ap-syndicate-dedup`, `patch-ap-syndicate-skip-checkin`, `patch-ap-syndicate-skip-draft`, `patch-ap-syndicate-skip-unlisted` +**Target file:** `lib/syndicator.js` + +**ORDERING CONSTRAINT:** dedup → checkin → draft → unlisted. Each patch's `newSnippet` is the next patch's `oldSnippet` anchor. Wrong order = silent skip. + +- [ ] **Read all 4 source scripts** to extract MARKER / OLD_SNIPPET / NEW_SNIPPET for each: + - `scripts/patch-ap-syndicate-dedup.mjs` + - `scripts/patch-ap-syndicate-skip-checkin.mjs` + - `scripts/patch-ap-syndicate-skip-draft.mjs` + - `scripts/patch-ap-syndicate-skip-unlisted.mjs` + +- [ ] **Create `scripts/patch-ap-syndication.mjs`** using the shared helper pattern above. + - Set `SCRIPT = "patch-ap-syndication"` + - All 4 patches use `files: apPath("lib/syndicator.js")` + - List PATCHES in order: dedup, checkin, draft, unlisted + +- [ ] **Verify against local node_modules:** + ```bash + node scripts/patch-ap-syndication.mjs + ``` + Expected: 4 lines of `applied patch-ap-syndicate-*` (or `already applied` if patches were previously applied). + If you see `snippet not found` — the ordering is wrong or the source script's OLD_SNIPPET differs from what's in the file. Re-read the source scripts. + +- [ ] **Commit:** + ```bash + git add scripts/patch-ap-syndication.mjs + git commit -m "feat: consolidated patch-ap-syndication (dedup, checkin, draft, unlisted)" + ``` + +--- + +## Task 2: Create `patch-ap-federation-infra.mjs` + +**Absorbs:** `patch-ap-federation-bridge-base-url`, `patch-ap-signature-host-header`, `patch-ap-inbox-delivery-debug`, `patch-ap-inbox-publication-url`, `patch-ap-webfinger-before-auth`, and `patch-ap-mastodon-delete-fix` **Change A only** (the `index.js` portion that exposes `broadcastDelete`) +**Target files:** `lib/federation-bridge.js`, `lib/federation-setup.js`, `index.js` + +- [ ] **Read all 6 source scripts:** + - `scripts/patch-ap-federation-bridge-base-url.mjs` + - `scripts/patch-ap-signature-host-header.mjs` + - `scripts/patch-ap-inbox-delivery-debug.mjs` + - `scripts/patch-ap-inbox-publication-url.mjs` + - `scripts/patch-ap-webfinger-before-auth.mjs` + - `scripts/patch-ap-mastodon-delete-fix.mjs` — **Change A only** (the snippet targeting `index.js`; Changes B and C target `statuses.js` and go in Task 3) + +- [ ] **Note `federation-bridge.js` vs `federation-setup.js`:** + `patch-ap-inbox-delivery-debug` targets two files. Read the script carefully — it patches one snippet in `federation-bridge.js` and one in `federation-setup.js`. Both get their own PATCHES entry with their respective `apPath()` calls. + +- [ ] **Note `patch-ap-federation-bridge-base-url` multi-file/multi-snippet:** + This script patches multiple files and/or multiple snippets (e.g., one change in `federation-bridge.js` and one in `index.js`). Each distinct file+snippet combination needs its own PATCHES entry. Do not try to merge them into a single entry — the `applyPatch` helper handles one snippet per call. + +- [ ] **ORDERING CONSTRAINT within `federation-bridge.js` entries:** + `patch-ap-inbox-delivery-debug`'s Fix B (the `federation-bridge.js` snippet) anchors on a comment injected by `patch-ap-federation-bridge-base-url` (specifically, the `// ap-base-url patch` comment in the surrounding code). In the PATCHES array, the `federation-bridge-base-url` entry for `federation-bridge.js` must appear **before** the `inbox-delivery-debug` entry for `federation-bridge.js`. Wrong order → delivery-debug snippet not found → silent skip. + +- [ ] **Create `scripts/patch-ap-federation-infra.mjs`** using the shared helper. + - Set `SCRIPT = "patch-ap-federation-infra"` + - Patches targeting `index.js` use `files: apPath("index.js")` — note: `index.js` is at the module root, not under `lib/` + - Apply federation-bridge-base-url entries before inbox-delivery-debug entries in the PATCHES array + +- [ ] **Verify:** + ```bash + node scripts/patch-ap-federation-infra.mjs + ``` + Expected: one `applied` or `already applied` line per patch (6 patches across 3+ files). + +- [ ] **Commit:** + ```bash + git add scripts/patch-ap-federation-infra.mjs + git commit -m "feat: consolidated patch-ap-federation-infra (bridge, signatures, inbox, webfinger, delete-fix Change A)" + ``` + +--- + +## Task 3: Create `patch-ap-mastodon-statuses.mjs` + +**Absorbs:** `patch-ap-mastodon-reply-threading`, `patch-ap-mastodon-status-id`, `patch-ap-mastodon-delete-fix` **Changes B and C only**, `patch-ap-status-reply-id` **Change B only**, `patch-ap-interactions-context-state` +**Target file:** `lib/mastodon/routes/statuses.js` + +- [ ] **Read 5 source scripts:** + - `scripts/patch-ap-mastodon-reply-threading.mjs` + - `scripts/patch-ap-mastodon-status-id.mjs` + - `scripts/patch-ap-mastodon-delete-fix.mjs` — Changes B and C only (skip the `index.js` Change A already handled in Task 2) + - `scripts/patch-ap-status-reply-id.mjs` — **Change B only**; Change A is upstream-fixed (the script's own upstream-fix guard skips it — include only Change B's OLD/NEW_SNIPPET) + - `scripts/patch-ap-interactions-context-state.mjs` + +- [ ] **For `patch-ap-status-reply-id` Change A:** The script checks whether the upstream fix is already present. For the consolidated script, simply omit Change A's snippet entirely — if it was needed, it would already be part of the upstream source. + +- [ ] **Create `scripts/patch-ap-mastodon-statuses.mjs`** using the shared helper. + - Set `SCRIPT = "patch-ap-mastodon-statuses"` + - All patches: `files: apPath("lib/mastodon/routes/statuses.js")` + +- [ ] **Verify:** + ```bash + node scripts/patch-ap-mastodon-statuses.mjs + ``` + Expected: one line per patch (5 patches). + +- [ ] **Commit:** + ```bash + git add scripts/patch-ap-mastodon-statuses.mjs + git commit -m "feat: consolidated patch-ap-mastodon-statuses (threading, status-id, delete, reply-id, interactions)" + ``` + +--- + +## Task 4: Create `patch-ap-mastodon-accounts.mjs` + +**Absorbs:** `patch-ap-actor-cache-await`, `patch-ap-resolve-account-timeout-safe` +**Target files:** `lib/mastodon/helpers/resolve-account.js` +**Drops:** `patch-ap-account-lookup-cache-fallback` — upstream already has the fix; script unconditionally skips. + +- [ ] **Read 2 source scripts:** + - `scripts/patch-ap-actor-cache-await.mjs` + - `scripts/patch-ap-resolve-account-timeout-safe.mjs` + +- [ ] **Create `scripts/patch-ap-mastodon-accounts.mjs`** using the shared helper. + - Set `SCRIPT = "patch-ap-mastodon-accounts"` + - Both patches target `resolve-account.js`: `files: apPath("lib/mastodon/helpers/resolve-account.js")` + - No ordering dependency between the two patches + +- [ ] **Verify:** + ```bash + node scripts/patch-ap-mastodon-accounts.mjs + ``` + Expected: 2 lines (applied or already applied). + +- [ ] **Commit:** + ```bash + git add scripts/patch-ap-mastodon-accounts.mjs + git commit -m "feat: consolidated patch-ap-mastodon-accounts (actor-cache-await, timeout-safe)" + ``` + +--- + +## Task 5: Create `patch-ap-mastodon-notifications.mjs` + +**Absorbs:** `patch-ap-notifications-status-lookup` +**Target file:** `lib/mastodon/routes/notifications.js` + +- [ ] **Read source script:** `scripts/patch-ap-notifications-status-lookup.mjs` + +- [ ] **Create `scripts/patch-ap-mastodon-notifications.mjs`** using the shared helper. + - Set `SCRIPT = "patch-ap-mastodon-notifications"` + - One patch: `files: apPath("lib/mastodon/routes/notifications.js")` + +- [ ] **Verify:** + ```bash + node scripts/patch-ap-mastodon-notifications.mjs + ``` + Expected: 1 line (applied or already applied). + +- [ ] **Commit:** + ```bash + git add scripts/patch-ap-mastodon-notifications.mjs + git commit -m "feat: consolidated patch-ap-mastodon-notifications (status-lookup)" + ``` + +--- + +## Task 6: Create `patch-ap-mastodon-misc.mjs` + +**Absorbs:** `patch-ap-compose-default-checked`, `patch-ap-og-image`, `patch-ap-repost-announce-fix`, `patch-ap-interactions-send-guard`, `patch-ap-interactions-cleanup-preserve`, `patch-ap-interactions-accounts-uid`, `patch-inbox-ignore-view-activity`, `patch-inbox-skip-view-activity-parse` +**Target files:** various (compose template, og-image handler, interactions handler, inbox handlers) + +- [ ] **Read all 8 source scripts** and note their exact target file paths (some will be under `lib/mastodon/routes/`, some under `lib/` root level or `lib/ap/`): + - `scripts/patch-ap-compose-default-checked.mjs` + - `scripts/patch-ap-og-image.mjs` + - `scripts/patch-ap-repost-announce-fix.mjs` + - `scripts/patch-ap-interactions-send-guard.mjs` + - `scripts/patch-ap-interactions-cleanup-preserve.mjs` + - `scripts/patch-ap-interactions-accounts-uid.mjs` + - `scripts/patch-inbox-ignore-view-activity.mjs` + - `scripts/patch-inbox-skip-view-activity-parse.mjs` + +- [ ] **Confirm candidate paths per patch** — some of these scripts may target files outside `lib/mastodon/` (e.g., compose template may be in `templates/`, inbox handlers may be in `lib/ap/`). Use exactly the candidate paths from each source script. + +- [ ] **Create `scripts/patch-ap-mastodon-misc.mjs`** using the shared helper. + - Set `SCRIPT = "patch-ap-mastodon-misc"` + - Each patch uses its correct `files` array (not all will use `apPath()` — copy candidate arrays verbatim from source scripts) + - No ordering dependencies — all patches target independent snippets or different files + +- [ ] **Verify:** + ```bash + node scripts/patch-ap-mastodon-misc.mjs + ``` + Expected: 8 lines (applied or already applied). + +- [ ] **Commit:** + ```bash + git add scripts/patch-ap-mastodon-misc.mjs + git commit -m "feat: consolidated patch-ap-mastodon-misc (compose, og-image, interactions, inbox)" + ``` + +--- + +## Task 7: Update `package.json` + +Replace the 27 individual AP patch invocations in both `postinstall` and `serve` with the 6 consolidated scripts (+ 2 standalone). + +- [ ] **Open `package.json`** and locate both `postinstall` and `serve` strings. + +- [ ] **In `postinstall`:** Remove these 27 entries (all `node scripts/patch-ap-*.mjs` and `node scripts/patch-inbox-*.mjs` that were consolidated or are dead): + - `patch-ap-skip-draft-syndication` (dead — drop entirely) + - `patch-ap-og-image` + - `patch-ap-webfinger-before-auth` + - `patch-ap-federation-bridge-base-url` + - `patch-ap-signature-host-header` + - `patch-ap-compose-default-checked` + - `patch-ap-mastodon-reply-threading` + - `patch-ap-mastodon-status-id` + - `patch-ap-interactions-send-guard` + - `patch-ap-interactions-cleanup-preserve` + - `patch-ap-interactions-accounts-uid` + - `patch-ap-interactions-context-state` + - `patch-ap-syndicate-dedup` + - `patch-ap-syndicate-skip-checkin` + - `patch-ap-syndicate-skip-draft` + - `patch-ap-syndicate-skip-unlisted` + - `patch-ap-mastodon-delete-fix` + - `patch-ap-status-reply-id` + - `patch-ap-inbox-publication-url` + - `patch-ap-inbox-delivery-debug` + - `patch-ap-repost-announce-fix` + - `patch-inbox-ignore-view-activity` + - `patch-inbox-skip-view-activity-parse` + - `patch-ap-actor-cache-await` + - `patch-ap-resolve-account-timeout-safe` + - `patch-ap-account-lookup-cache-fallback` (dead — drop entirely) + - `patch-ap-notifications-status-lookup` + + The 27 removed entries currently span from `patch-ap-skip-draft-syndication` through `patch-ap-notifications-status-lookup`, with `patch-ap-startup-gate-bypass` interleaved near the end of that block (just before `patch-micropub-category-from-posts`). When deleting the block, keep `patch-ap-startup-gate-bypass` in place — remove everything around it, not the entry itself. + + After removal, the `patch-ap-startup-gate-bypass` entry stays at its current position in `postinstall`. Insert the 6 consolidated scripts immediately after it, before `patch-micropub-category-from-posts`: + ``` + node scripts/patch-ap-startup-gate-bypass.mjs && + node scripts/patch-ap-oauth-token-expiry-fix.mjs && + node scripts/patch-ap-federation-infra.mjs && + node scripts/patch-ap-syndication.mjs && + node scripts/patch-ap-mastodon-statuses.mjs && + node scripts/patch-ap-mastodon-accounts.mjs && + node scripts/patch-ap-mastodon-notifications.mjs && + node scripts/patch-ap-mastodon-misc.mjs && + node scripts/patch-micropub-category-from-posts.mjs && ... + ``` + +- [ ] **In `serve`:** Apply the same replacement logic. `patch-ap-startup-gate-bypass` must remain **first** in `serve` (it already is the first entry in the serve script — do not move it). + +- [ ] **Verify the JSON is valid:** + ```bash + node -e "require('./package.json')" && echo "valid" + ``` + Expected: `valid` + +- [ ] **Dry-run the full postinstall sequence** (without actually running npm install — just run the consolidated scripts manually in order): + ```bash + node scripts/patch-ap-federation-infra.mjs && \ + node scripts/patch-ap-syndication.mjs && \ + node scripts/patch-ap-mastodon-statuses.mjs && \ + node scripts/patch-ap-mastodon-accounts.mjs && \ + node scripts/patch-ap-mastodon-notifications.mjs && \ + node scripts/patch-ap-mastodon-misc.mjs + ``` + Expected: all report `already applied` (since Tasks 1-6 already applied them). No `snippet not found` warnings. + +- [ ] **Commit:** + ```bash + git add package.json + git commit -m "refactor: replace 27 individual AP patches with 6 consolidated scripts in postinstall/serve" + ``` + +--- + +## Task 8: Delete old scripts + +- [ ] **Delete the 27 consolidated/dead source scripts:** + ```bash + cd "/Users/sven/Library/Mobile Documents/com~apple~CloudDocs/PARA/1. Projects/indiekit-server" + git rm \ + scripts/patch-ap-skip-draft-syndication.mjs \ + scripts/patch-ap-og-image.mjs \ + scripts/patch-ap-webfinger-before-auth.mjs \ + scripts/patch-ap-federation-bridge-base-url.mjs \ + scripts/patch-ap-signature-host-header.mjs \ + scripts/patch-ap-compose-default-checked.mjs \ + scripts/patch-ap-mastodon-reply-threading.mjs \ + scripts/patch-ap-mastodon-status-id.mjs \ + scripts/patch-ap-interactions-send-guard.mjs \ + scripts/patch-ap-interactions-cleanup-preserve.mjs \ + scripts/patch-ap-interactions-accounts-uid.mjs \ + scripts/patch-ap-interactions-context-state.mjs \ + scripts/patch-ap-syndicate-dedup.mjs \ + scripts/patch-ap-syndicate-skip-checkin.mjs \ + scripts/patch-ap-syndicate-skip-draft.mjs \ + scripts/patch-ap-syndicate-skip-unlisted.mjs \ + scripts/patch-ap-mastodon-delete-fix.mjs \ + scripts/patch-ap-status-reply-id.mjs \ + scripts/patch-ap-inbox-publication-url.mjs \ + scripts/patch-ap-inbox-delivery-debug.mjs \ + scripts/patch-ap-repost-announce-fix.mjs \ + scripts/patch-inbox-ignore-view-activity.mjs \ + scripts/patch-inbox-skip-view-activity-parse.mjs \ + scripts/patch-ap-actor-cache-await.mjs \ + scripts/patch-ap-resolve-account-timeout-safe.mjs \ + scripts/patch-ap-account-lookup-cache-fallback.mjs \ + scripts/patch-ap-notifications-status-lookup.mjs + ``` + +- [ ] **Verify no references remain in package.json:** + ```bash + grep -c "patch-ap-syndicate-dedup\|patch-ap-account-lookup-cache-fallback\|patch-ap-skip-draft-syndication" package.json + ``` + Expected: `0` + +- [ ] **Commit:** + ```bash + git commit -m "refactor: delete 27 consolidated/dead AP patch scripts" + ``` + +--- + +## Task 9: Final verification + +- [ ] **Count remaining AP patch scripts:** + ```bash + ls scripts/patch-ap-*.mjs scripts/patch-inbox-*.mjs 2>/dev/null + ``` + Expected: exactly these files remain: + - `patch-ap-startup-gate-bypass.mjs` + - `patch-ap-oauth-token-expiry-fix.mjs` + - `patch-ap-syndication.mjs` + - `patch-ap-federation-infra.mjs` + - `patch-ap-mastodon-statuses.mjs` + - `patch-ap-mastodon-accounts.mjs` + - `patch-ap-mastodon-notifications.mjs` + - `patch-ap-mastodon-misc.mjs` + +- [ ] **Simulate a clean postinstall:** + ```bash + npm run postinstall 2>&1 | grep -E "(patch-ap|patch-inbox|snippet not found|ERROR)" + ``` + If `node_modules` is already patched, all scripts report `already applied` — that's fine and expected. No `snippet not found`, no errors. + +- [ ] **Deep verify — confirm MARKERs are present in actual node_modules files** (this catches cases where a patch silently skipped on first run): + ```bash + # Syndicator: expect 4 markers + grep -c '\[patch\] ap-syndicate' node_modules/@rmdes/indiekit-endpoint-activitypub/lib/syndicator.js + # statuses.js: expect at least 4 markers + grep -c '\[patch\] ap-' node_modules/@rmdes/indiekit-endpoint-activitypub/lib/mastodon/routes/statuses.js + # resolve-account.js: expect 2 markers + grep -c '\[patch\] ap-' node_modules/@rmdes/indiekit-endpoint-activitypub/lib/mastodon/helpers/resolve-account.js + # notifications.js: expect 1 marker + grep -c '\[patch\] ap-' node_modules/@rmdes/indiekit-endpoint-activitypub/lib/mastodon/routes/notifications.js + ``` + If any count is 0 and the patch should have been applied, re-run the consolidated script directly and check for `snippet not found` warnings. + +- [ ] **Check package.json postinstall line length** (long lines can cause shell issues on some systems): + ```bash + node -e "const p = require('./package.json'); console.log('postinstall:', p.scripts.postinstall.length, 'chars'); console.log('serve:', p.scripts.serve.length, 'chars')" + ``` + Both should be noticeably shorter than before (was ~3000 chars each). + +- [ ] **Tag and push:** + ```bash + git log --oneline -8 + git push + ``` diff --git a/docs/superpowers/specs/2026-04-12-ap-patch-consolidation-design.md b/docs/superpowers/specs/2026-04-12-ap-patch-consolidation-design.md index e0fe97cd..1371e970 100644 --- a/docs/superpowers/specs/2026-04-12-ap-patch-consolidation-design.md +++ b/docs/superpowers/specs/2026-04-12-ap-patch-consolidation-design.md @@ -65,7 +65,6 @@ The following AP-adjacent patches target non-AP packages or have standalone comp - `patch-ap-oauth-token-expiry-fix` — targets `mastodon/routes/oauth.js`; standalone auth fix - `patch-ap-startup-gate-bypass` — targets startup-gate package; runs first in serve, before other patches -- `patch-ap-mastodon-delete-fix` — already absorbed into `patch-ap-mastodon-statuses` Non-AP patches (bluesky, micropub, webmention, etc.) are out of scope.