Skip to content

fix(api): correct seven live-verb defects and repoint the GitHub issue routes - #24

Merged
Adron merged 1 commit into
devfrom
fix/live-verb-defects-v1-v7
Sep 6, 2026
Merged

fix(api): correct seven live-verb defects and repoint the GitHub issue routes#24
Adron merged 1 commit into
devfrom
fix/live-verb-defects-v1-v7

Conversation

@Adron

@Adron Adron commented Sep 6, 2026

Copy link
Copy Markdown
Member

Fixes the seven live-verb defects catalogued as work-consolidation.md §1c · V1–V7, plus the G27 one-off routes as a follow-on.

Seven shipping calls sent an HTTP verb — or, in V3 and V7, a path and body shape — the live API does not accept, so the feature behind each failed against production. Every fix here was confirmed twice before it was written: the live OPTIONS Allow header, and an authenticated round trip against the .env test account.

The probes found more than §1c recorded

All eight Allow headers matched the doc exactly. But OPTIONS proves which verb is accepted, never the body shape or response envelope — and exercising each corrected call live turned up compounding defects:

# Documented What was actually needed
V1 PUTPATCH PATCH is a reschedule route, not a message editor — see below
V2 POSTPATCH ✅ exactly as documented
V3 PATCHPUT plus request field rowDatadata, plus a {message, data} envelope — and the same two defects on createRow and the single-row read
V4 PATCHPUT plus the {message, organization} envelope on create, read and update
V5 PATCHPUT plus the {message, folder} envelope on create, read and update
V6 POSTDELETE ✅ as documented
V7 repoint to flat paths paths correct, but the route sets labels/assignees only

Fixing only the verb on V3/V4/V5 would have swapped a 405 for a decode failure.

Two of these are missing backend capabilities, not verb typos

This is the substantive half of the change, and it contradicts what §1c assumed:

  • Editing a posted message has no live route. PATCH /api/messages/{id} honours only scheduledAt, answers 400 "No valid updates provided" to a content body, silently discards content sent alongside scheduledAt (confirmed: stored content unchanged while scheduledAt moved), and refuses an already-published post outright. Messages.update is replaced by Messages.reschedule; MessagesService.update — which had no App-layer caller — now throws MessagesError.editingNotSupported rather than issuing a call that cannot succeed.
  • Closing / reopening a GitHub issue has no live route. PATCH /api/github/issues/{owner}/{repo}/{number} requires labels or assignees; a state/title/body body returns 400 "labels or assignees required". GitHubService.updateIssue now refuses such an update up front with GitHubServiceError.unsupportedIssueEdit, and the dead Close/Reopen button was removed from the issue detail bar rather than left to fail. "Open on GitHub" is the working path.

Adjacent scope, and why it is here

Probing G27's PUT /api/documents/{id} revealed that documents themselves answer a {message, document} envelope on create, read and update — so opening and saving a document also failed at the decoder. Same defect class, same files already being edited; fixing folders while leaving documents broken would have been half a repair.

G27 — small self-contained gaps (follow-on)

All probed live before being built:

  • DELETE /api/notifications/{id} — 204, no body.
  • POST /api/messages/{id}/reply-counts — per-platform tallies; count is absent for an unsupported platform, so it decodes as nil rather than a misleading 0.
  • GET /api/user/engagementresolves the open "may be session-only" note: 401 under Bearer, 200 over a cookie session, so it is declared auth: .session.
  • PUT /api/documents/{id} — the full-replace variant beside the existing PATCH.

Tests

  • LiveVerbDefectRegressionTests — locks all seven verbs, the flat GitHub paths, the corrected request bodies and the response envelopes.
  • SmallGapEndpointTests — BDD coverage for the four G27 routes.
  • BDD quartets for the new reschedule path and both unsupported-edit refusals.
  • An env-gated ContractTests case that re-reads the live Allow headers on every CI pass, so the client cannot drift off the API again unnoticed. It is read-only (OPTIONS mutates nothing) and skips without credentials.

Existing tests that asserted the broken verbs were updated, not deleted — each now carries a comment naming the live behaviour it encodes.

Beyond curl, the corrected Swift builders were exercised end-to-end against production (create → read → update → delete for organizations, folders, list rows and documents, plus the session-auth engagement route). All probe data was cleaned up and the account verified clear of artifacts.

Gate

  • xcodebuild -scheme InterlinedList -destination 'platform=macOS' build** BUILD SUCCEEDED **
  • xcodebuild … test (App target) → ** TEST SUCCEEDED **
  • swift test — InterlinedKit 337, InterlinedDomain 625, InterlinedPersistence 135, SyncAgent 53 — all green
  • grep -rn "import InterlinedKit" App/Features App/Navigation App/MenuCommands0 hits

Notes for the reviewer

  • work-consolidation.md is deliberately untouched. The §1c section exists only on the docs branch; editing it here would guarantee a conflict. Its V1 and V7 rows, and the P2-I / P1-H2 entries, still describe the old understanding and need rewriting — both capability gaps above are new backend asks.
  • One real notification was deleted from the test account while probing DELETE /api/notifications/{id}.

🤖 Generated with Claude Code

https://claude.ai/code/session_013tAJgfBGnnA1HgRGAWvkRK

…e routes

Seven shipping calls sent an HTTP verb (or path, or body field) the live API
does not accept, so the feature behind each failed against production. Each fix
below was confirmed twice before it was written: the live `OPTIONS` `Allow`
header, and an authenticated round trip against the `.env` test account.

work-consolidation.md §1c · V1–V7:

- V1 `Messages.update` — PUT was 405. Replaced with `Messages.reschedule`:
  PATCH is a **reschedule** route, not a message editor. It honours only
  `scheduledAt`, answers 400 "No valid updates provided" to a content body,
  silently discards `content` sent beside `scheduledAt`, refuses an
  already-published post, and returns a bare MessageDTO rather than the create
  envelope. Editing a posted message has no live route, so
  `MessagesService.update` now throws `MessagesError.editingNotSupported`
  instead of issuing a call that cannot succeed.
- V2 `User.update` — POST → PATCH. Settings ▸ Preferences could never save.
- V3 `Lists.updateRow` — wrong in three ways: PATCH → PUT, request field
  `rowData` → `data`, and the reply is a `{message, data}` envelope. The same
  field and envelope defects applied to `createRow` and the single-row read, so
  list rows could not be created, opened or edited.
- V4 `Organizations.update` — PATCH → PUT, plus the `{message, organization}`
  envelope on create, read and update.
- V5 `Documents.updateFolder` — PATCH → PUT, plus the `{message, folder}`
  envelope on create, read and update.
- V6 `Follow.remove` — POST → DELETE.
- V7 GitHub issue update + comment — the nested `/api/github/repos/...` paths
  404. Both are flat: `/api/github/issues/{owner}/{repo}/{number}[/comments]`.
  The update route sets **labels and assignees only** — a state/title/body body
  is refused 400 "labels or assignees required" — so close/reopen has no live
  route. `GitHubService.updateIssue` rejects such an update up front with
  `GitHubServiceError.unsupportedIssueEdit`, and the dead Close/Reopen button
  was removed from the issue detail bar rather than left to fail.

Found while probing, same defect class, same files: documents themselves answer
a `{message, document}` envelope on create/read/update, so opening and saving a
document also failed at the decoder. Fixed alongside.

work-consolidation.md G27 (small self-contained gaps), all probed live first:

- `DELETE /api/notifications/{id}` — 204, no body.
- `POST /api/messages/{id}/reply-counts` — returns per-platform tallies where
  `count` is absent for an unsupported platform.
- `GET /api/user/engagement` — resolves the open "may be session-only" note: it
  401s under Bearer and returns 200 over a cookie session, so it is declared
  `auth: .session`.
- `PUT /api/documents/{id}` — full-replace variant beside the existing PATCH.

Tests: a `LiveVerbDefectRegressionTests` suite locking all seven verbs, the flat
GitHub paths, the request bodies and the response envelopes; a
`SmallGapEndpointTests` suite for G27; BDD quartets for the new reschedule and
unsupported-edit paths; and an env-gated `ContractTests` case that re-reads the
live `Allow` headers so the client cannot drift off the API again unnoticed.
Existing tests that asserted the broken verbs were updated, not deleted.

Gate: App build SUCCEEDED, App tests SUCCEEDED, Kit 337 / Domain 625 /
Persistence 135 / SyncAgent 53 tests all green, zero InterlinedKit imports in
App/Features|Navigation|MenuCommands.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013tAJgfBGnnA1HgRGAWvkRK
@Adron
Adron merged commit 282c031 into dev Sep 6, 2026
7 of 8 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