Skip to content

Absorb additive activity-timeline event fields (bc3 #11629)#424

Open
jeremy wants to merge 1 commit into
tool-visible-to-clientsfrom
timeline-additive-fields
Open

Absorb additive activity-timeline event fields (bc3 #11629)#424
jeremy wants to merge 1 commit into
tool-visible-to-clientsfrom
timeline-additive-fields

Conversation

@jeremy

@jeremy jeremy commented Jul 25, 2026

Copy link
Copy Markdown
Member

Closes #423. Part of the post-#401 BC3 follow-up absorption program (PR-2).

Stacked on #419 (PR-1) → #416 (PR-0). Base is tool-visible-to-clients; review the PR-2 commit only. Will retarget to main as the stack merges.

Summary

The merged doc/api/sections/timeline.md and the bc3 timeline event view (api/timelines/events/_event.json.jbuilder) carry event fields the SDK did not yet type. No new operationsGetProgressReport, GetProjectTimeline, and GetPersonProgress already model the three routes. This extends TimelineEvent.

Additive fields

  • kind — kept an open, non-exhaustive String (doc only, no closed enum). Documents live-only values (project_access_changed, dock_created, google_document_created).
  • dataTimelineEventData for schedule_entry_* events. starts_at/ends_at are date-or-timestamp (bare date when all_day is true), so not plain timestamps: ISO8601Timestamp in Smithy (mirroring ScheduleEntry) + a Go types.FlexibleTime enhancement; other SDKs type them as strings.
  • avatars_sampleStringList.
  • attachmentsheterogeneous (full Upload recording vs rich-text attachment/blob partial). These variants share no required field set, so "reuse the existing attachment shape" is false. Modeled as an optional-field superset struct (TimelineAttachment) — the untagged-polymorphism default; no union needed. width/height get the nullable *types.FlexInt Go enhancement.

Runtime decode proof (all six SDKs)

Every SDK — Go, TS, Ruby, Python, Kotlin, Swift — has a non-empty, per-variant test decoding BOTH attachment variants in one array, plus the all-day date-only data payload and a non-empty avatars_sample. Empty-array / generator-shape checks were treated as insufficient. The Go wrapper's TimelineAttachment routes decoding through the generated FlexInt type via a custom UnmarshalJSON (mirroring RichTextAttachment).

Verification

make generate && make check — clean. Added a GetProgressReport entry to the live-my-surface canary (validates statically; live canary dormant). Flipped activity-timeline.mdabsorbed-in-sdk with smithy_refs.


Summary by cubic

Extends TimelineEvent to absorb the remaining activity‑timeline fields so event payloads match BC3 across all SDKs. No new routes.

  • New Features
    • kind: open string; documents common values like project_access_changed, dock_created, google_document_created.
    • data: TimelineEventData for schedule entries with date‑or‑timestamp bounds; Go decodes with types.FlexibleTime.
    • avatars_sample: array of avatar URLs.
    • attachments: heterogeneous superset TimelineAttachment (full Upload vs rich‑text blob); Go width/height use nullable types.FlexInt with presence‑faithful decode.
    • Verification: added per‑SDK tests asserting both attachment variants, all‑day date‑only data, and non‑empty avatars_sample; added a GetProgressReport canary for static schema validation.

Written for commit 2643d82. Summary will update on new commits.

Review in cubic

Copilot AI review requested due to automatic review settings July 25, 2026 04:54
@github-actions github-actions Bot added typescript Pull requests that update TypeScript code ruby Pull requests that update the Ruby SDK go kotlin swift spec Changes to the Smithy spec or OpenAPI conformance Conformance test suite labels Jul 25, 2026
@github-actions

github-actions Bot commented Jul 25, 2026

Copy link
Copy Markdown

Spec Change Impact

Changes:

  • Modified types: Added new fields to the activity-timeline event type.
  • No operations or resources were added or removed.

SDK Impact:

  • All SDKs require regeneration due to spec modification.

Breaking Change:

  • No, this is not a breaking API change (new fields are additive, no removals).

Checklist for SDK Updates:

  • Go
  • TypeScript
  • Ruby
  • Kotlin
  • Swift

@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: 99171dbb13

ℹ️ 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/basecamp/timeline.go Outdated
Comment on lines +79 to +80
CreatedAt time.Time `json:"created_at,omitempty"`
UpdatedAt time.Time `json:"updated_at,omitempty"`

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Make optional attachment timestamps pointers

When a rich-text/blob attachment is decoded and later marshaled—for example by a consumer caching or proxying a TimelineEvent—these fields remain zero-valued because that variant has no upload timestamps. Go's encoding/json does not treat a zero time.Time struct as empty for omitempty, so the output gains created_at and updated_at values such as 0001-01-01T00:00:00Z, contradicting the optional-variant model and changing the payload. Represent these optional timestamps as pointers (or add custom marshaling that omits zero values).

Useful? React with 👍 / 👎.

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

This PR absorbs additive activity-timeline event fields from BC3 into the shared Smithy/OpenAPI surface, extending TimelineEvent (no new operations) so SDK consumers can decode kind, schedule-entry data, avatars_sample, and heterogeneous attachments consistently across languages.

Changes:

  • Extended Smithy TimelineEvent with kind, avatars_sample, data: TimelineEventData, and attachments: TimelineAttachmentList, plus added TimelineEventData + TimelineAttachment shapes.
  • Propagated the new shapes through generated OpenAPI artifacts and language SDK models (TS/Ruby/Python/Swift/Kotlin) and the Go generated client + wrapper conversion.
  • Added per-SDK runtime decode tests asserting non-empty avatars_sample, all-day date-only data bounds, and both attachment variants in one array; added a conformance live-surface schema validation entry.

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 13 out of 26 changed files in this pull request and generated no comments.

Show a summary per file
File Description
spec/basecamp.smithy Adds the new additive timeline fields and supporting shapes (TimelineEventData/TimelineAttachment).
scripts/enhance-openapi-go-types.sh Applies Go-only OpenAPI type enhancements (FlexibleTime for date-or-timestamp; FlexInt for nullable dimensions).
openapi.json Regenerated OpenAPI including new timeline schemas and descriptions.
go/pkg/generated/client.gen.go Regenerated Go client types for the new schemas.
go/pkg/basecamp/timeline.go Updates the Go public wrapper types + conversion and adds attachment JSON unmarshalling via generated FlexInt.
go/pkg/basecamp/timeline_test.go Adds Go decode proof covering avatars/data and both attachment variants.
typescript/src/generated/openapi-stripped.json Regenerated TS OpenAPI input with new schemas.
typescript/src/generated/schema.d.ts Updates TS schema typings for new fields/shapes.
typescript/src/generated/metadata.ts Regenerated TS metadata timestamp.
typescript/tests/services/timeline.test.ts Adds TS decode test for avatars/data and both attachment variants.
ruby/lib/basecamp/generated/types.rb Regenerated Ruby types to include the new timeline shapes.
ruby/lib/basecamp/generated/metadata.json Regenerated Ruby metadata timestamp.
ruby/test/basecamp/services/timeline_service_test.rb Adds Ruby decode test for avatars/data and both attachment variants.
python/src/basecamp/generated/types.py Regenerated Python TypedDicts for new timeline shapes.
python/tests/services/test_timeline.py Adds Python decode test for avatars/data and both attachment variants.
swift/Sources/Basecamp/Generated/Models/TimelineEvent.swift Regenerated Swift model to include new fields.
swift/Sources/Basecamp/Generated/Models/TimelineEventData.swift New Swift generated model for schedule-entry timeline event data.
swift/Sources/Basecamp/Generated/Models/TimelineAttachment.swift New Swift generated model for the heterogeneous attachment superset.
swift/Tests/BasecampTests/GeneratedServiceTests.swift Adds Swift decode test for avatars/data and both attachment variants.
kotlin/sdk/src/commonMain/kotlin/com/basecamp/sdk/generated/models/TimelineEvent.kt Regenerated Kotlin model to include new fields.
kotlin/sdk/src/commonMain/kotlin/com/basecamp/sdk/generated/models/TimelineEventData.kt New Kotlin generated model for schedule-entry timeline event data.
kotlin/sdk/src/commonMain/kotlin/com/basecamp/sdk/generated/models/TimelineAttachment.kt New Kotlin generated model for heterogeneous attachment superset (with flexible int serializer).
kotlin/sdk/src/commonTest/kotlin/com/basecamp/sdk/TimelineDecodeTest.kt Adds Kotlin decode test for avatars/data and both attachment variants.
spec/api-gaps/README.md Marks activity-timeline gap as absorbed-in-sdk.
spec/api-gaps/activity-timeline.md Updates the gap entry to absorbed-in-sdk with smithy refs and absorption notes.
conformance/tests/live-my-surface.json Adds a GetProgressReport live-surface schema validation entry covering the new fields.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@cubic-dev-ai cubic-dev-ai 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.

9 issues found across 26 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="kotlin/sdk/src/commonTest/kotlin/com/basecamp/sdk/TimelineDecodeTest.kt">

<violation number="1" location="kotlin/sdk/src/commonTest/kotlin/com/basecamp/sdk/TimelineDecodeTest.kt:89">
P3: Add assertions on `kind` for one or more events — this is a new additive field being introduced and the fixture already covers multiple values.</violation>

<violation number="2" location="kotlin/sdk/src/commonTest/kotlin/com/basecamp/sdk/TimelineDecodeTest.kt:111">
P3: Missing assertion on `height` for the Upload variant — both width and height use FlexibleIntSerializer and should be verified symmetrically.</violation>

<violation number="3" location="kotlin/sdk/src/commonTest/kotlin/com/basecamp/sdk/TimelineDecodeTest.kt:120">
P3: Missing assertion on `height` for the RichText variant — width is checked for null but height (also null in fixture) is not.</violation>
</file>

<file name="python/tests/services/test_timeline.py">

<violation number="1" location="python/tests/services/test_timeline.py:38">
P2: The test does not exercise a heterogeneous `attachments` array: the Upload and blob variants are in separate event arrays, so a decoder that mishandles the second element would still pass. Put both records in one `attachments` list and assert both elements.</violation>
</file>

<file name="typescript/tests/services/timeline.test.ts">

<violation number="1" location="typescript/tests/services/timeline.test.ts:65">
P3: The fixture supplies the newly documented `kind` field, but the test never verifies it. An explicit typed assertion for `events[0]!.kind` would cover this TimelineEvent addition instead of making the fixture value unobserved.</violation>

<violation number="2" location="typescript/tests/services/timeline.test.ts:87">
P3: The test does not verify heterogeneous attachments in one response array: each array contains only one variant. A decoder or generated model that handles homogeneous arrays but fails when Upload and blob entries are mixed would pass this test.</violation>
</file>

<file name="go/pkg/basecamp/timeline_test.go">

<violation number="1" location="go/pkg/basecamp/timeline_test.go:89">
P3: The additive-field test does not actually decode both attachment variants from one heterogeneous `attachments` array: the upload and blob cases are in separate event arrays. Combining both objects under one event would make the test match the claimed coverage and catch slice-level polymorphic regressions.</violation>
</file>

<file name="go/pkg/basecamp/timeline.go">

<violation number="1" location="go/pkg/basecamp/timeline.go:84">
P2: A decoded upload with `visible_to_clients: false` loses that explicit API value on re-marshal because `omitempty` suppresses false. Keep the bool field tagged without `omitempty`.

(Based on your team's feedback about bool serialization.) [FEEDBACK_USED]</violation>

<violation number="2" location="go/pkg/basecamp/timeline.go:92">
P2: A non-previewable blob loses its explicit `previewable: false` value on re-marshal. Keep the bool field tagged without `omitempty`.

(Based on your team's feedback about bool serialization.) [FEEDBACK_USED]</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

"created_at": "2024-03-15T10:32:00Z",
"kind": "upload_created",
"avatars_sample": [],
"attachments": [

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: The test does not exercise a heterogeneous attachments array: the Upload and blob variants are in separate event arrays, so a decoder that mishandles the second element would still pass. Put both records in one attachments list and assert both elements.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At python/tests/services/test_timeline.py, line 38:

<comment>The test does not exercise a heterogeneous `attachments` array: the Upload and blob variants are in separate event arrays, so a decoder that mishandles the second element would still pass. Put both records in one `attachments` list and assert both elements.</comment>

<file context>
@@ -0,0 +1,119 @@
+            "created_at": "2024-03-15T10:32:00Z",
+            "kind": "upload_created",
+            "avatars_sample": [],
+            "attachments": [
+                {
+                    "id": 900,
</file context>

Comment thread go/pkg/basecamp/timeline.go Outdated
StatusURL string `json:"status_url,omitempty"`
Caption string `json:"caption,omitempty"`
Key string `json:"key,omitempty"`
Previewable bool `json:"previewable,omitempty"`

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: A non-previewable blob loses its explicit previewable: false value on re-marshal. Keep the bool field tagged without omitempty.

(Based on your team's feedback about bool serialization.)

View Feedback

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At go/pkg/basecamp/timeline.go, line 92:

<comment>A non-previewable blob loses its explicit `previewable: false` value on re-marshal. Keep the bool field tagged without `omitempty`.

(Based on your team's feedback about bool serialization.) </comment>

<file context>
@@ -8,25 +8,90 @@ import (
+	StatusURL      string `json:"status_url,omitempty"`
+	Caption        string `json:"caption,omitempty"`
+	Key            string `json:"key,omitempty"`
+	Previewable    bool   `json:"previewable,omitempty"`
+	PreviewURL     string `json:"preview_url,omitempty"`
+	ThumbnailURL   string `json:"thumbnail_url,omitempty"`
</file context>
Suggested change
Previewable bool `json:"previewable,omitempty"`
Previewable bool `json:"previewable"`

Comment thread go/pkg/basecamp/timeline.go Outdated
RecordingURL string `json:"url,omitempty"`
AppURL string `json:"app_url,omitempty"`
AppDownloadURL string `json:"app_download_url,omitempty"`
VisibleToClients bool `json:"visible_to_clients,omitempty"`

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: A decoded upload with visible_to_clients: false loses that explicit API value on re-marshal because omitempty suppresses false. Keep the bool field tagged without omitempty.

(Based on your team's feedback about bool serialization.)

View Feedback

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At go/pkg/basecamp/timeline.go, line 84:

<comment>A decoded upload with `visible_to_clients: false` loses that explicit API value on re-marshal because `omitempty` suppresses false. Keep the bool field tagged without `omitempty`.

(Based on your team's feedback about bool serialization.) </comment>

<file context>
@@ -8,25 +8,90 @@ import (
+	RecordingURL     string    `json:"url,omitempty"`
+	AppURL           string    `json:"app_url,omitempty"`
+	AppDownloadURL   string    `json:"app_download_url,omitempty"`
+	VisibleToClients bool      `json:"visible_to_clients,omitempty"`
+
+	// Rich-text attachment/blob variant.
</file context>
Suggested change
VisibleToClients bool `json:"visible_to_clients,omitempty"`
VisibleToClients bool `json:"visible_to_clients"`

Comment thread go/pkg/basecamp/timeline.go Outdated
assertEquals("See attached", blob[0].caption)
assertEquals("blobkey500", blob[0].key)
assertTrue(blob[0].previewable)
assertNull(blob[0].width)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P3: Missing assertion on height for the RichText variant — width is checked for null but height (also null in fixture) is not.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At kotlin/sdk/src/commonTest/kotlin/com/basecamp/sdk/TimelineDecodeTest.kt, line 120:

<comment>Missing assertion on `height` for the RichText variant — width is checked for null but height (also null in fixture) is not.</comment>

<file context>
@@ -0,0 +1,122 @@
+        assertEquals("See attached", blob[0].caption)
+        assertEquals("blobkey500", blob[0].key)
+        assertTrue(blob[0].previewable)
+        assertNull(blob[0].width)
+    }
+}
</file context>

assertEquals("Upload", upload[0].type)
assertEquals("diagram.png", upload[0].filename)
assertEquals("https://3.basecamp.com/1/buckets/2/uploads/900/download", upload[0].appDownloadUrl)
assertEquals(1024, upload[0].width)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P3: Missing assertion on height for the Upload variant — both width and height use FlexibleIntSerializer and should be verified symmetrically.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At kotlin/sdk/src/commonTest/kotlin/com/basecamp/sdk/TimelineDecodeTest.kt, line 111:

<comment>Missing assertion on `height` for the Upload variant — both width and height use FlexibleIntSerializer and should be verified symmetrically.</comment>

<file context>
@@ -0,0 +1,122 @@
+        assertEquals("Upload", upload[0].type)
+        assertEquals("diagram.png", upload[0].filename)
+        assertEquals("https://3.basecamp.com/1/buckets/2/uploads/900/download", upload[0].appDownloadUrl)
+        assertEquals(1024, upload[0].width)
+
+        // Event 3: rich-text attachment/blob partial variant.
</file context>

@@ -0,0 +1,122 @@
package com.basecamp.sdk

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P3: Add assertions on kind for one or more events — this is a new additive field being introduced and the fixture already covers multiple values.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At kotlin/sdk/src/commonTest/kotlin/com/basecamp/sdk/TimelineDecodeTest.kt, line 89:

<comment>Add assertions on `kind` for one or more events — this is a new additive field being introduced and the fixture already covers multiple values.</comment>

<file context>
@@ -0,0 +1,122 @@
+        ]
+    """.trimIndent()
+
+    @Test
+    fun decodesAdditiveTimelineFields() {
+        val events = json.decodeFromString<List<TimelineEvent>>(fixtureJson)
</file context>

created_at: "2024-03-15T10:32:00Z",
kind: "upload_created",
avatars_sample: [],
attachments: [

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P3: The test does not verify heterogeneous attachments in one response array: each array contains only one variant. A decoder or generated model that handles homogeneous arrays but fails when Upload and blob entries are mixed would pass this test.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At typescript/tests/services/timeline.test.ts, line 87:

<comment>The test does not verify heterogeneous attachments in one response array: each array contains only one variant. A decoder or generated model that handles homogeneous arrays but fails when Upload and blob entries are mixed would pass this test.</comment>

<file context>
@@ -54,5 +54,116 @@ describe("TimelineService", () => {
+          created_at: "2024-03-15T10:32:00Z",
+          kind: "upload_created",
+          avatars_sample: [],
+          attachments: [
+            {
+              id: 900,
</file context>

{
id: 1,
created_at: "2024-03-15T10:30:00Z",
kind: "chat_transcript_rollup",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P3: The fixture supplies the newly documented kind field, but the test never verifies it. An explicit typed assertion for events[0]!.kind would cover this TimelineEvent addition instead of making the fixture value unobserved.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At typescript/tests/services/timeline.test.ts, line 65:

<comment>The fixture supplies the newly documented `kind` field, but the test never verifies it. An explicit typed assertion for `events[0]!.kind` would cover this TimelineEvent addition instead of making the fixture value unobserved.</comment>

<file context>
@@ -54,5 +54,116 @@ describe("TimelineService", () => {
+        {
+          id: 1,
+          created_at: "2024-03-15T10:30:00Z",
+          kind: "chat_transcript_rollup",
+          avatars_sample: [
+            "https://3.basecampapi.com/1/people/aaa/avatar",
</file context>

// fields: a non-empty avatars_sample, the schedule-entry data payload with a
// date-only (all_day) starts_at/ends_at, and BOTH heterogeneous attachment
// variants — a full Upload recording and a rich-text attachment/blob partial —
// in a single non-empty array. Empty arrays / shape-only tests do not prove

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P3: The additive-field test does not actually decode both attachment variants from one heterogeneous attachments array: the upload and blob cases are in separate event arrays. Combining both objects under one event would make the test match the claimed coverage and catch slice-level polymorphic regressions.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At go/pkg/basecamp/timeline_test.go, line 89:

<comment>The additive-field test does not actually decode both attachment variants from one heterogeneous `attachments` array: the upload and blob cases are in separate event arrays. Combining both objects under one event would make the test match the claimed coverage and catch slice-level polymorphic regressions.</comment>

<file context>
@@ -82,6 +82,145 @@ func TestTimelineEvent_Unmarshal(t *testing.T) {
+// fields: a non-empty avatars_sample, the schedule-entry data payload with a
+// date-only (all_day) starts_at/ends_at, and BOTH heterogeneous attachment
+// variants — a full Upload recording and a rich-text attachment/blob partial —
+// in a single non-empty array. Empty arrays / shape-only tests do not prove
+// polymorphic decode, so both variants carry real per-variant fields here.
+func TestTimelineEvent_AdditiveFields(t *testing.T) {
</file context>

The merged doc/api/sections/timeline.md and the bc3 timeline event view
(api/timelines/events/_event.json.jbuilder) carry event fields the SDK did
not yet type. No new operations — GetProgressReport, GetProjectTimeline, and
GetPersonProgress already model the three routes. Extend TimelineEvent:

- kind: kept an open, non-exhaustive String (documentation only, no closed
  enum) — BC3 adds new kinds over time; document common values including the
  live-only project_access_changed, dock_created, google_document_created.
- data: new TimelineEventData sub-struct for schedule_entry_* events. Per the
  bc3 view (starts_at_date_or_time), starts_at/ends_at are date-or-timestamp
  (a bare date when all_day is true), so they are NOT plain timestamps:
  modeled as ISO8601Timestamp mirroring ScheduleEntry, with a Go enhancement
  pass mapping them to types.FlexibleTime; other SDKs type them as strings.
- avatars_sample: StringList (chat-rollup participants).
- attachments: heterogeneous per the bc3 view — an upload-kind recording
  contributes its full Upload shape, every other recording a rich-text
  attachment/blob partial. These variants share no required field set, so
  reusing an existing attachment shape is not possible. Modeled as an
  optional-field superset struct (TimelineAttachment) so one element type
  decodes either variant (the untagged-polymorphism default; no union needed).
  width/height get the nullable *types.FlexInt Go enhancement (float-spelled
  1024.0, null for non-image blobs), matching RichTextAttachment.

Runtime decode proof: every SDK (Go, TS, Ruby, Python, Kotlin, Swift) has a
non-empty, per-variant test decoding BOTH attachment variants in one array,
plus the all-day date-only data payload and a non-empty avatars_sample. The
Go wrapper's TimelineAttachment routes decoding through the generated FlexInt
type via a custom UnmarshalJSON (mirroring RichTextAttachment).

Add a GetProgressReport entry to the live-my-surface canary (validates
statically; live canary dormant) and flip activity-timeline.md to
absorbed-in-sdk with smithy_refs.
Copilot AI review requested due to automatic review settings July 25, 2026 07:08
@jeremy
jeremy force-pushed the timeline-additive-fields branch from 99171db to 2643d82 Compare July 25, 2026 07:08
@github-actions github-actions Bot added the enhancement New feature or request label Jul 25, 2026

@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: 2643d8213f

ℹ️ 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".

val url: String? = null,
@SerialName("app_url") val appUrl: String? = null,
@SerialName("app_download_url") val appDownloadUrl: String? = null,
@SerialName("visible_to_clients") val visibleToClients: Boolean = false,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve absence for optional Kotlin attachment booleans

When decoding the rich-text/blob variant, visible_to_clients is absent—as demonstrated by the new fixture—but this default exposes it as false, making that absence indistinguishable from an upload variant that explicitly sends visible_to_clients: false. This defeats the optional-field superset's documented presence semantics and the SDK's optional-field contract; generate this as Boolean? = null (and likewise preserve presence for the other optional primitive variant fields) by fixing the Kotlin model generator rather than patching generated output.

AGENTS.md reference: AGENTS.md:L68-L70

Useful? React with 👍 / 👎.

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

Copilot reviewed 13 out of 26 changed files in this pull request and generated 2 comments.

Comments suppressed due to low confidence (3)

typescript/tests/services/timeline.test.ts:154

  • This test casts to any, which bypasses the generated TimelineEvent type and reduces the value of the test as a schema/typing guard. Prefer accessing the typed field directly (and non-null assert based on the fixture).
      const upload = (events[2] as any).attachments[0];

typescript/tests/services/timeline.test.ts:161

  • This test casts to any, which bypasses the generated TimelineEvent type and reduces the value of the test as a schema/typing guard. Prefer accessing the typed field directly (and non-null assert based on the fixture).
      const blob = (events[3] as any).attachments[0];

typescript/tests/services/timeline.test.ts:148

  • This test casts to any, which bypasses the generated TimelineEvent type and reduces the value of the test as a schema/typing guard. Prefer accessing the typed field directly (using a non-null assertion since the fixture includes it).
      const data = (events[1] as any).data;

Comment on lines +7 to +10
smithy_refs:
- "TimelineEvent.kind/avatars_sample/data/attachments (spec/basecamp.smithy:7479)"
- "TimelineEventData (spec/basecamp.smithy:7527)"
- "TimelineAttachment (spec/basecamp.smithy:7543)"
expect(events).toHaveLength(4);

// avatars_sample is a non-empty array of avatar URLs
const avatars = (events[0] as any).avatars_sample;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

conformance Conformance test suite enhancement New feature or request go kotlin ruby Pull requests that update the Ruby SDK spec Changes to the Smithy spec or OpenAPI swift typescript Pull requests that update TypeScript code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants