Skip to content

Bug: refreshMessageMetadata decodes a response shape the route never sends — always returns [] #104

Description

@Adron

Found while implementing #96 (see PR #103), and verified independently against the backend source.

The mismatch

APIClient.refreshMessageMetadata (Services/APIClient.swift:382-391) decodes:

struct Response: Decodable {
    struct Meta: Decodable { let links: [MessageLinkPreview]? }
    let metadata: Meta?          // <- expects a nested "metadata" object
}
return response.metadata?.links ?? []

app/api/messages/[id]/metadata/route.ts returns, at both exit points (:86, :105):

return NextResponse.json(serialize({ links: linkMetadataItems }), …)

Top level links, no metadata wrapper. serialize() normalizes values; it never restructures.
So response.metadata is always nil and the function always returns [] against the live API.

Each entry is also a full LinkMetadataItem — nested metadata object, thumbnail rather than
image, plus platform / fetchStatus / fetchedAt. MessageLinkPreview's flat
{url,title,description,image} shape matches nothing the backend sends; the closest existing type is
CanonicalLinkPreview, which uses imageUrl.

The test is the worrying part

test_refreshMessageMetadata_* passes today. It passes because its fixture was hand-written to the
assumed shape rather than a captured response. So the suite actively asserts the wrong contract.

This is the response-direction twin of the defaultVisibility bug (#46): there, a request key the
route ignored; here, a response shape the route never produces. Both are green-and-wrong.

Build this

  • Decode what the route actually returns: top-level links, entries shaped as LinkMetadataItem.
    Prefer reusing LinkMetadataItem over keeping MessageLinkPreview alive — check whether
    MessageLinkPreview has any other consumer first; if not, delete it with its tests.
  • Rewrite the test fixture from the route source (or a captured live response), not from the
    Swift type. Add a comment in the test naming the route file it was derived from.
  • Confirm the same mistake is not present in the sibling GET on that route (:47-48 returns
    the same { links } shape).

Acceptance criteria

Blocks

#103 / #96 are inert until this lands. Does not affect #94, which ignores the response — the POST
still causes the server to fetch and persist metadata.

Files: Services/APIClient.swift:382, Models/Message.swift,
InterlinedListTests/APIClientTests/*.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingws:papercutsW8 — small parity papercuts

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions