Absorb additive activity-timeline event fields (bc3 #11629)#424
Conversation
Spec Change ImpactChanges:
SDK Impact:
Breaking Change:
Checklist for SDK Updates:
|
There was a problem hiding this comment.
💡 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".
| CreatedAt time.Time `json:"created_at,omitempty"` | ||
| UpdatedAt time.Time `json:"updated_at,omitempty"` |
There was a problem hiding this comment.
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 👍 / 👎.
There was a problem hiding this comment.
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
TimelineEventwithkind,avatars_sample,data: TimelineEventData, andattachments: TimelineAttachmentList, plus addedTimelineEventData+TimelineAttachmentshapes. - 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-onlydatabounds, 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.
There was a problem hiding this comment.
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": [ |
There was a problem hiding this comment.
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>
| StatusURL string `json:"status_url,omitempty"` | ||
| Caption string `json:"caption,omitempty"` | ||
| Key string `json:"key,omitempty"` | ||
| Previewable bool `json:"previewable,omitempty"` |
There was a problem hiding this comment.
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.)
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>
| Previewable bool `json:"previewable,omitempty"` | |
| Previewable bool `json:"previewable"` |
| 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"` |
There was a problem hiding this comment.
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.)
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>
| VisibleToClients bool `json:"visible_to_clients,omitempty"` | |
| VisibleToClients bool `json:"visible_to_clients"` |
| assertEquals("See attached", blob[0].caption) | ||
| assertEquals("blobkey500", blob[0].key) | ||
| assertTrue(blob[0].previewable) | ||
| assertNull(blob[0].width) |
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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 | |||
There was a problem hiding this comment.
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: [ |
There was a problem hiding this comment.
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", |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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>
da1cf30 to
d43ed91
Compare
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.
99171db to
2643d82
Compare
There was a problem hiding this comment.
💡 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, |
There was a problem hiding this comment.
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 👍 / 👎.
There was a problem hiding this comment.
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 generatedTimelineEventtype 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 generatedTimelineEventtype 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 generatedTimelineEventtype 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;
| 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; |
Closes #423. Part of the post-#401 BC3 follow-up absorption program (PR-2).
Summary
The merged
doc/api/sections/timeline.mdand 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, andGetPersonProgressalready model the three routes. This extendsTimelineEvent.Additive fields
kind— kept an open, non-exhaustiveString(doc only, no closed enum). Documents live-only values (project_access_changed,dock_created,google_document_created).data—TimelineEventDataforschedule_entry_*events.starts_at/ends_atare date-or-timestamp (bare date whenall_dayis true), so not plain timestamps:ISO8601Timestampin Smithy (mirroringScheduleEntry) + a Gotypes.FlexibleTimeenhancement; other SDKs type them as strings.avatars_sample—StringList.attachments— heterogeneous (fullUploadrecording 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.FlexIntGo 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
datapayload and a non-emptyavatars_sample. Empty-array / generator-shape checks were treated as insufficient. The Go wrapper'sTimelineAttachmentroutes decoding through the generatedFlexInttype via a customUnmarshalJSON(mirroringRichTextAttachment).Verification
make generate && make check— clean. Added aGetProgressReportentry to thelive-my-surfacecanary (validates statically; live canary dormant). Flippedactivity-timeline.md→absorbed-in-sdkwith smithy_refs.Summary by cubic
Extends
TimelineEventto absorb the remaining activity‑timeline fields so event payloads match BC3 across all SDKs. No new routes.kind: open string; documents common values likeproject_access_changed,dock_created,google_document_created.data:TimelineEventDatafor schedule entries with date‑or‑timestamp bounds; Go decodes withtypes.FlexibleTime.avatars_sample: array of avatar URLs.attachments: heterogeneous supersetTimelineAttachment(full Upload vs rich‑text blob); Gowidth/heightuse nullabletypes.FlexIntwith presence‑faithful decode.data, and non‑emptyavatars_sample; added aGetProgressReportcanary for static schema validation.Written for commit 2643d82. Summary will update on new commits.