Skip to content

Let a reply carry its subject - #134

Merged
jeremy merged 2 commits into
mainfrom
fix/reply-subject
Aug 31, 2026
Merged

Let a reply carry its subject#134
jeremy merged 2 commits into
mainfrom
fix/reply-subject

Conversation

@jeremy

@jeremy jeremy commented Aug 31, 2026

Copy link
Copy Markdown
Member

ReplyMessagePayload modeled only content, so a reply had no way to carry a subject. HEY never derives one: the server permits message[subject] on POST /entries/{id}/replies.json, and NewEntryReply hands back the prefilled "Re: …" subject — but the model provided nowhere to send it back, so every reply draft the SDK saved showed as "No subject" in HEY's Drafts.

Change

  • spec/hey.smithy: optional subject on ReplyMessagePayload, with wire-format docs; openapi.json and client.gen.go regenerated.
  • EntriesService.CreateReply and CreateReplyDraft take subject ahead of content, mirroring MessagesService.Create. An empty subject stays off the wire (omitempty), leaving today's requests byte-identical.
  • Content stays the caller's reply body alone: the server appends the quoted original at delivery (auto_quoting defaults on), so the prefill's quoted content must not be echoed back — now documented on the payload.

Tests

  • Unit: subject asserted on the wire for both reply and reply-draft paths; empty subject asserted absent; the old draft test asserting subject must not be sent (built on the "a reply stays under its thread's subject" misconception) flipped.
  • Conformance: CreateReply case now round-trips message.subject.
  • make check green (MVP gate, 168/168 conformance).

Breaking signature change to the two wrappers; hey-cli follow-up passes the prefill subject through: basecamp/hey-cli#370 (pins this branch's commit; bumps to the tagged release once this merges).

Basecamp: A reply can't carry a subject — every reply draft saves as "No subject"
Fixes the subject leg of basecamp/hey-cli#341.


Summary by cubic

Lets a reply carry its subject, so reply drafts no longer save as "No subject" in HEY's Drafts. ReplyMessagePayload gains an optional subject that stays off the wire when empty; content remains the caller's reply body alone.

Breaking change

Written for commit 44894c6. Summary will update on new commits.

Review in cubic

ReplyMessagePayload had only content, so every reply draft the SDK saved
showed as "No subject" in HEY's Drafts: the server permits
message[subject] on POST /entries/{id}/replies.json but never derives
one, and NewEntryReply hands back the prefilled "Re: …" subject with
nowhere to send it back.

Add an optional subject to ReplyMessagePayload in the Smithy model,
regenerate, and take it in the CreateReply and CreateReplyDraft
wrappers. An empty subject stays off the wire, leaving today's requests
byte-identical. Content remains the caller's reply body alone — the
server appends the quoted original at delivery via auto_quoting, so the
prefill's quoted content must not be echoed back.
Copilot AI balanced review requested due to automatic review settings August 31, 2026 22:10
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Aug 31, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-08-31T22:30:26.624457Z 44894c6 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds reply subjects throughout the Smithy-to-Go pipeline so saved reply drafts retain their prefilled subject.

Changes:

  • Models and serializes optional reply subjects.
  • Updates reply service signatures and tests.
  • Extends conformance coverage.

Tip

If you aren't ready for review, convert to a draft PR.
Click "Convert to draft" or run gh pr ready --undo.
Click "Ready for review" or run gh pr ready to reengage.

Reviewed changes

Copilot reviewed 8 out of 9 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
spec/hey.smithy Models and documents reply subjects.
openapi.json Regenerates the OpenAPI schema.
go/pkg/generated/client.gen.go Regenerates Go payload types.
go/pkg/hey/entries.go Accepts subjects in reply wrappers.
go/pkg/hey/services_test.go Tests reply subject serialization.
go/pkg/hey/drafts_test.go Tests draft reply subjects.
go/pkg/hey/account_scope_test.go Updates the reply call signature.
conformance/tests/paths.json Adds subject wire assertions.
conformance/runner/go/main.go Passes subjects in conformance requests.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread go/pkg/hey/entries.go

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: eebd6024ee

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread go/pkg/hey/entries.go
CreateReply now takes the subject before the body, which the quick-start
still called in the old shape, and which apidiff rightly reports as an
incompatible change — deliberately so, this being a v0.x SDK whose point
here is the new parameter. Teach the gate about deliberate breaks via
.github/apidiff-accepted: exact apidiff output lines, matched whole, so
an entry names the old signature and can never mask a later accidental
change reported from the new baseline.
@jeremy
jeremy merged commit ed5cf6f into main Aug 31, 2026
18 checks passed
@jeremy
jeremy deleted the fix/reply-subject branch August 31, 2026 22:36
jeremy added a commit that referenced this pull request Sep 1, 2026
* Send a reply as the sender the prefill resolved

CreateReply and CreateReplyDraft always filled acting_sender_id from
DefaultSenderID — the account's default sender — ignoring the sender
HEY resolved for the thread. The reply prefill (NewEntryReply) picks
its sender by inspecting the entry's own to and from addresses, so on
a shared or alternate address (a HEY for Work support address, an
extension, a forwarded external account) the SDK delivered every
reply as the account owner instead: the wrong identity, every time.

Take an actingSenderID on both wrappers, sent as acting_sender_id
untouched; zero keeps today's DefaultSenderID fallback. Pass the
prefill's Sender.Id — NewReply already hands it back, present exactly
when it differs from the acting user. No wire or spec change:
acting_sender_id was always sent, it just carried the wrong value.

A deliberate v0.x signature break, acknowledged in apidiff-accepted
alongside the reply-subject one (#134).

* Carry the chosen sender through the draft lifecycle; pass ids through untouched

DraftContent takes an ActingSenderID, so a draft saved as an alternate
identity survives UpdateDraft and SendDraft instead of being handed back
to the account default — HEY revises a draft from the whole of what is
sent, acting_sender_id included. Resolution moves onto the Client, where
every DraftContent consumer and both reply wrappers share it, and only
zero means the default now: any other id reaches the server as given,
an invalid one being the server's to reject rather than the SDK's to
silently rewrite. The conformance CreateReply case asserts the id on the
wire, and the README example checks the prefill read before leaning on
it.

* Exercise the reply wrappers in conformance at the HEY layer

The generated-client case copies the fixture id into the request itself,
so it proves nothing about the wrappers this change touches. Dispatch
CreateReply and CreateReplyDraft through executeHEYOperation and assert
the chosen acting_sender_id, subject, content and recipients on the wire
from the hand-written layer. The zero fallback stays a unit-test concern:
it resolves DefaultSenderID via an identity fetch, and requestBody
assertions read the first recorded request.

* Cover the draft lifecycle's sender carriage in conformance

CreateDraft, UpdateDraft and SendDraft dispatch through
executeHEYOperation now, each asserting the chosen acting_sender_id on
the wire along with the lifecycle's status semantics: drafted on save
and revision, omitted on the delivering send.

* Carry cc and bcc through the reply conformance dispatch; honest README reply

The reply dispatch dropped any cc or bcc a case supplied; all three
recipient kinds ride now. The quick-start reply stops swallowing a
failed prefill read and addresses the reply with the recipients the
prefill resolved rather than a hardcoded one.
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.

2 participants