Summary
A single place to record and act on the remaining backend dependencies. Each carries a paste-ready prompt for the InterlinedList API session (base URL https://interlinedlist.com). None of these can be closed from the client.
Nothing here blocks the rest of the parity work — every other open parity issue is client-buildable today. This issue exists so the asks are tracked rather than rediscovered on each sweep.
1. Following / home feed — the one high-impact blocker
Re-verified still broken 2026-09-05. An authenticated GET /api/messages?limit=50 and GET /api/messages?limit=50&scope=following return the identical 50 messages from the identical author set, a month after the first report. MessagesService.timeline short-circuits .following to an empty "coming soon" page (MessagesService.swift:364); the All/Mine/Following picker is fully wired and flips one branch the moment the feed exists.
This also blocks the Following Only option in the viewing-preference work.
PROMPT: Add a followed-accounts timeline feed. Preferred: extend GET /api/messages with ?scope=following (or add GET /api/feed/following), returning only messages authored by accounts the caller follows, using the same paginated envelope as GET /api/messages (same limit/offset/hasMore shape). Bearer auth. Document it. Note: as of 2026-09-05 the live server silently ignores scope/feed/following/filter on GET /api/messages, so this needs a real implementation, not just docs. The macOS client already has the UI wired and flips one branch to consume it.
2. Session-only routes lock out every Bearer client
The live OpenAPI spec declares 45 operations as x-auth-type: session — "requires the web session cookie only; a Bearer token is not accepted". Setting aside admin, cron, Stripe, and architecture-aggregates, these are the ones a native app legitimately needs:
| Route |
What it costs the native client |
POST /api/lists/invite/{token} |
Cannot accept a list email invite |
POST /api/documents/invite/{token} |
Cannot accept a document email invite |
POST /api/lists/shared/{token} |
Cannot claim an editor/admin list share link |
POST /api/documents/shared/{token} |
Cannot claim an editor/admin document share link |
POST /api/auth/send-verification-email |
Cannot offer Resend verification email |
GET /api/user/engagement |
No engagement stats (confirmed 401 under Bearer, 2026-09-07) |
GET/PUT /api/user/dashboard-layout |
Dashboard is unbuildable |
GET/PUT /api/user/front-wall-layout |
Front wall is unbuildable |
GET /api/widgets/*, and by extension the widget surface |
Widgets are unbuildable |
GET /api/auth/accounts, POST /api/auth/switch, POST /api/auth/remove-account |
Multi-account switching is unbuildable |
The read halves (GET /api/lists/invite/{token} etc.) are public, so the client can show an invite landing page and then hand the user to the browser to accept — a poor but honest experience.
Note the spec's own prose is stale here: its description lists "exports, organizations, LinkedIn targets, GitHub helpers, message dig, message edit" as session-only, but the per-operation x-auth-type values show all of those as sync-token. Worth flagging in the same ask.
PROMPT: The macOS client authenticates with a Bearer sync token (POST /api/auth/sync-token). Several operations are declared x-auth-type: session and reject Bearer, which makes them unreachable for native and CLI clients. Please make the following Bearer-reachable, or document a supported alternative: (1) the claim/accept halves of the invite and share-link flows — POST /api/lists/invite/{token}, POST /api/documents/invite/{token}, POST /api/lists/shared/{token}, POST /api/documents/shared/{token}. Accepting an invite is documented as always free, so there is no entitlement reason for the restriction. (2) POST /api/auth/send-verification-email, so a native app can offer the documented "Resend verification email" action. (3) GET /api/user/engagement. Separately: the OpenAPI info.description lists exports, organizations, LinkedIn targets, GitHub helpers, message dig, and message edit as session-only, but their per-operation x-auth-type is sync-token — please reconcile the prose with the operation values.
3. article_series returns 502 provider_error on every attempt
Found 2026-09-05, re-confirmed 2026-09-06. POST /api/ai/suggest {"feature":"article_series"} fails with {"error":"The AI provider rejected the request.","code":"provider_error"} on three separate attempts across two days, with different briefs, all well over the ten-word minimum. The same account, key, and model succeed for writing_assist, message_series, powered_template, and powered_document — so it is not entitlement, quota, or input length. The macOS client blames the provider rather than the user, so it degrades honestly, but Article Series cannot work for any client until this is fixed.
PROMPT: POST /api/ai/suggest with {"feature":"article_series","input":"<a multi-sentence brief>"} returns 502 {"error":"The AI provider rejected the request.","code":"provider_error"} every time, for a subscriber whose other AI features (writing_assist, message_series, powered_template, powered_document) all succeed on the same request path. Reproduced three times across 2026-09-05 and 2026-09-06 with different briefs. Please check the article_series prompt/schema construction and what the provider is actually rejecting — likely a malformed tool/response schema for that feature specifically — and confirm the artifact shape it should return (the other features return {artifact:{kind,…}}).
4. GitHub issue shapes still cannot be exercised end-to-end
The test account is GitHub-linked now (GET /api/github/repos → 200, up from the old 400 "not linked"), but the repo list comes back empty and GET /api/github/orgs returns [] — so issue create/update/comment request and response envelopes remain unverified. The routes are settled (PR #24 repointed the client at the flat three-segment paths); only the payloads are unknown.
This one may not need the backend at all — granting the .env test account access to a single repository would unblock it locally. Try that first.
5. Smaller confirmations and additive niceties
Each is worked around today; these make the client correct or cheaper. Additive fields are always safe — the client decodes by name and ignores unknowns.
- Auth decision on
GET /api/messages (returns 200 with public content and no Authorization header). No client change either way; needs a documented decision. (P1-F)
- Follow action returns
followedBy — the client decodes {follow:{status}} and needs a second GET /api/follow/{userId}/status call. A relationship block on the follow/unfollow/approve/reject responses removes a round-trip. (P2-B)
- Typed notification kinds +
routePath — deep-linking works via a client-side typed projection; a stable routePath collapses it to a plain URL and unblocks APNs push routing. (P2-C)
- Markdown export —
/api/exports/* is CSV-only, so the client renders Markdown itself, costing N+1 refetches for bulk export. (P2-F)
- Schema DSL
select/markdown token spec — Field:select(a|b|c) is a client convention, still API-unconfirmed. This blocks the per-field validation work. (P2-G)
- Document version / ETag for sync conflict detection. (P3-A)
folderId on sync-response documents, including preserved copies and deleted documents. (P3-B)
- GitHub-backed list refresh metadata +
githubSource on create — lastRefreshedAt, refreshStatus, refreshError; blocks part of the GitHub-backed-lists work. (P3-C)
RateLimit-* headers universally — currently only on POST /api/messages and POST /api/documents/sync. (P3-E)
- List clone-with-rows — "save to my lists" copies title/description/schema but no rows, because no clone endpoint exists. (P3-G)
Full paste-ready prompts for each live in work-consolidation.md §2c.
Acceptance criteria
- Each numbered item is either resolved upstream or explicitly deferred with a reason.
- When one lands, the client-side issue it blocks is unblocked and linked here.
Notes
Consolidates work-consolidation.md §2a and §2c. Re-verify before acting — three items previously filed as backend blockers (P1-H2, P2-I, P3-D) turned out to be client-side errors and were fixed in PR #24/#25. Probe first, ask second.
Summary
A single place to record and act on the remaining backend dependencies. Each carries a paste-ready prompt for the InterlinedList API session (base URL
https://interlinedlist.com). None of these can be closed from the client.Nothing here blocks the rest of the parity work — every other open parity issue is client-buildable today. This issue exists so the asks are tracked rather than rediscovered on each sweep.
1. Following / home feed — the one high-impact blocker
Re-verified still broken 2026-09-05. An authenticated
GET /api/messages?limit=50andGET /api/messages?limit=50&scope=followingreturn the identical 50 messages from the identical author set, a month after the first report.MessagesService.timelineshort-circuits.followingto an empty "coming soon" page (MessagesService.swift:364); the All/Mine/Following picker is fully wired and flips one branch the moment the feed exists.This also blocks the
Following Onlyoption in the viewing-preference work.2. Session-only routes lock out every Bearer client
The live OpenAPI spec declares 45 operations as
x-auth-type: session— "requires the web session cookie only; a Bearer token is not accepted". Setting aside admin, cron, Stripe, and architecture-aggregates, these are the ones a native app legitimately needs:POST /api/lists/invite/{token}POST /api/documents/invite/{token}POST /api/lists/shared/{token}POST /api/documents/shared/{token}POST /api/auth/send-verification-emailGET /api/user/engagementGET/PUT /api/user/dashboard-layoutGET/PUT /api/user/front-wall-layoutGET /api/widgets/*, and by extension the widget surfaceGET /api/auth/accounts,POST /api/auth/switch,POST /api/auth/remove-accountThe read halves (
GET /api/lists/invite/{token}etc.) are public, so the client can show an invite landing page and then hand the user to the browser to accept — a poor but honest experience.Note the spec's own prose is stale here: its description lists "exports, organizations, LinkedIn targets, GitHub helpers, message dig, message edit" as session-only, but the per-operation
x-auth-typevalues show all of those assync-token. Worth flagging in the same ask.3.
article_seriesreturns 502provider_erroron every attemptFound 2026-09-05, re-confirmed 2026-09-06.
POST /api/ai/suggest {"feature":"article_series"}fails with{"error":"The AI provider rejected the request.","code":"provider_error"}on three separate attempts across two days, with different briefs, all well over the ten-word minimum. The same account, key, and model succeed forwriting_assist,message_series,powered_template, andpowered_document— so it is not entitlement, quota, or input length. The macOS client blames the provider rather than the user, so it degrades honestly, but Article Series cannot work for any client until this is fixed.4. GitHub issue shapes still cannot be exercised end-to-end
The test account is GitHub-linked now (
GET /api/github/repos→ 200, up from the old 400 "not linked"), but the repo list comes back empty andGET /api/github/orgsreturns[]— so issue create/update/comment request and response envelopes remain unverified. The routes are settled (PR #24 repointed the client at the flat three-segment paths); only the payloads are unknown.This one may not need the backend at all — granting the
.envtest account access to a single repository would unblock it locally. Try that first.5. Smaller confirmations and additive niceties
Each is worked around today; these make the client correct or cheaper. Additive fields are always safe — the client decodes by name and ignores unknowns.
GET /api/messages(returns 200 with public content and noAuthorizationheader). No client change either way; needs a documented decision. (P1-F)followedBy— the client decodes{follow:{status}}and needs a secondGET /api/follow/{userId}/statuscall. Arelationshipblock on the follow/unfollow/approve/reject responses removes a round-trip. (P2-B)routePath— deep-linking works via a client-side typed projection; a stableroutePathcollapses it to a plain URL and unblocks APNs push routing. (P2-C)/api/exports/*is CSV-only, so the client renders Markdown itself, costing N+1 refetches for bulk export. (P2-F)select/markdowntoken spec —Field:select(a|b|c)is a client convention, still API-unconfirmed. This blocks the per-field validation work. (P2-G)folderIdon sync-response documents, including preserved copies and deleted documents. (P3-B)githubSourceon create —lastRefreshedAt,refreshStatus,refreshError; blocks part of the GitHub-backed-lists work. (P3-C)RateLimit-*headers universally — currently only onPOST /api/messagesandPOST /api/documents/sync. (P3-E)Full paste-ready prompts for each live in
work-consolidation.md§2c.Acceptance criteria
Notes
Consolidates
work-consolidation.md§2a and §2c. Re-verify before acting — three items previously filed as backend blockers (P1-H2,P2-I,P3-D) turned out to be client-side errors and were fixed in PR #24/#25. Probe first, ask second.