Skip to content

Support episode custom properties - #176

Merged
brookfxg merged 6 commits into
mainfrom
brook/dc-1873-update-python-library-episode-custom-properties
Oct 28, 2026
Merged

brookfxg merged 6 commits into
mainfrom
brook/dc-1873-update-python-library-episode-custom-properties

Conversation

@brookfxg

@brookfxg brookfxg commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Changelog

Adds support for Episode Versioning and Properties

Product updates

None.

Links

DC-1873

Related API rollout: foxglove/app#21090. This is not a release dependency for default dataset exports.

Implementation details

Bulk updates support version preconditions, recording membership, time bounds, and property removal through None. Episode reads expose version and latest_version, and property dictionaries preserve user-defined keys.

Dataset exports default to include_properties=False, preserving existing requests and manifests for organizations outside the property allowlist. Explicit opt-in requests properties and adds them to the manifest, including empty property objects; omitted response fields remain omitted. Default exports do not depend on removing the server gate.

Testing

  • Against an API with episode properties enabled, create an episode with properties, update it using applies_to_version, and confirm a stale version is rejected.
  • Filter episodes and dataset membership by a property, request property inclusion, and confirm the returned values match.
  • Export a committed dataset and confirm manifest.json contains the selected episodes' custom properties.
  • Export with default options and confirm the manifest omits properties. Repeat with include_properties=True in an enabled organization and confirm properties are included.

Add properties to episode creation, a bulk update_episodes method for the
PATCH /v1/episodes endpoint, include_properties and properties_query on
episode and dataset episode reads, and episode version fields on returned
episodes. Dataset downloads now record each episode's properties in the
manifest, matching the app's export.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@linear-code

linear-code Bot commented Oct 27, 2026

Copy link
Copy Markdown

DC-1873

@brookfxg
brookfxg marked this pull request as ready for review October 27, 2026 22:52
@brookfxg
brookfxg requested a review from mguida22 as a code owner October 27, 2026 22:52
foxglove-beefcake[bot]

This comment was marked as outdated.

foxglove-beefcake[bot]

This comment was marked as outdated.

@foxglove-beefcake foxglove-beefcake 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.

LGTM

@foxglove-beefcake foxglove-beefcake 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.

LGTM

- Drop the note that episode properties require API access.
- Drop the example topic filter so the example downloads all topics.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@foxglove-beefcake foxglove-beefcake 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.

LGTM

@mguida22 mguida22 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

download_dataset reads the committed episode snapshot but streams using only episodeId, which resolves to the latest version. After bounds or recordings change, the MCAP can disagree with the manifest. Please pass the snapshot’s episode["version"] as episodeVersion when requesting the stream.

@mguida22
mguida22 dismissed their stale review October 28, 2026 18:44

Changing this feedback to a comment-only review at the reviewer's request.

@mguida22 mguida22 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

download_dataset reads the committed episode snapshot but streams using only episodeId, which resolves to the latest version. After bounds or recordings change, the MCAP can disagree with the manifest. Please pass the snapshot’s episode["version"] as episodeVersion when requesting the stream.

download_dataset reads each episode from the committed version's snapshot
but signed stream links with only episodeId, which resolves to the latest
version. After an episode's bounds or recordings changed, the MCAP could
disagree with the manifest. Pass the snapshot's version as episodeVersion,
matching the app's dataset download.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@foxglove-beefcake foxglove-beefcake 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.

LGTM

@brookfxg

Copy link
Copy Markdown
Contributor Author

download_dataset reads the committed episode snapshot but streams using only episodeId, which resolves to the latest version. After bounds or recordings change, the MCAP can disagree with the manifest. Please pass the snapshot’s episode["version"] as episodeVersion when requesting the stream.

Fixed.

@brookfxg
brookfxg requested a review from mguida22 October 28, 2026 19:28
@brookfxg
brookfxg merged commit 9e86850 into main Oct 28, 2026
2 checks passed
@brookfxg
brookfxg deleted the brook/dc-1873-update-python-library-episode-custom-properties branch October 28, 2026 20:56
brookfxg added a commit to foxglove/foxglove-cli that referenced this pull request Oct 28, 2026
### Changelog

None

### Docs

None

### Description

The CLI can now create and edit episode custom properties, filter
episode and dataset membership lists, and include properties in reads,
comparisons, and dataset manifests. It follows the existing device
`--property key:value` convention and adds `episodes edit ID` with
property removal, time-bound and recording changes, and optional
`--applies-to-version`.

**Defaults and rollout:** `--include-properties` defaults to false
everywhere, matching Python PR
[#176](foxglove/foxglove-python#176). Ordinary
reads and downloads make no property requests, and default manifests
omit properties. Creation without properties makes no definition lookup
and omits the field. All rollout checks remain on the API; enabling API
access requires no subsequent CLI change. Explicit property operations
and all episode edits can return 403 while access is disabled; the CLI
surfaces those failures without a fallback or mutation retry.

Episode reads retain the API's required `version` and `latestVersion`,
and `episodes get --version N` selects a historical snapshot.
Comparisons retain both snapshots of changed episodes and report changed
counts. JSON gains these fields, and episode/membership table and CSV
output append Version, Latest Version, and Custom Properties columns.
Comparisons also append Previous Version and Previous Custom Properties.
Consumers expecting an exact output layout may need to adjust.

Dataset download property inclusion preserves `{}` versus omission.
Resume runs refresh manifest properties without invalidating completed
MCAPs, including checkpoint entries copied from an earlier run. A failed
property lookup leaves existing download files and manifests intact. The
manifest format version, selection fields, and stream requests are
unchanged.

Typed assignment requires `properties.list` plus the operation's
capability. As with device syntax, repeated multi-enum values replace
the property's complete list; this change does not add syntax for
assigning an empty multi-enum array. Property removals send null.
Existing dataset pins remain on their selected episode versions.

This implements the agreed property/read/edit/export scope of
[DC-1872](https://linear.app/foxglove/issue/DC-1872/update-cli-to-support-episode-properties-and-versions);
it does not close that broader issue. Bulk editing, history listing,
dataset pin mutation commands, and stream-version changes are outside
this PR. Existing PRs
[#220](#220),
[#222](#222), and
[#225](#225) overlap the
read/edit/comparison areas but target the older labels contract. This PR
is standalone against main and uses custom properties.

Validated locally on macOS with the pinned Rust toolchain:

- `make rust-lint`: formatting and Clippy passed with warnings denied.
- `make rust-test-ignored`: 118 unit tests and 128 integration tests
passed, including loopback HTTP contracts for defaults, typed values,
removals, filtering, historical reads, comparison snapshots,
gate/auth/conflict errors, pagination, resume toggles, and checkpoint
preservation.
- `make rust-doc` and `make build`: passed.
- `make rust-audit`: completed successfully; existing informational
warnings for `unsafe-libyaml` (RUSTSEC-2024-0449) and `tokio`
(RUSTSEC-2026-0386). Dependencies and lockfile are unchanged.
- Verified all seven affected command help pages and generated Bash,
Fish, PowerShell, and Zsh completions.

Live API smoke tests and deployment verification have not been
performed. The implementation targets the version-aware API contract,
whose version fields are independent of the property allowlist.

The commands below illustrate the supported behavior; HTTP behavior is
verified through local fixtures.

<table><tr><th>Before</th><th>After</th></tr>
<tr><td>Episode creation could not assign custom
properties.</td><td><code>foxglove episodes add --recording-id
rec_example --property weather:rain</code> creates or reuses the
matching episode with typed properties.</td></tr>
<tr><td>Single-episode editing was unavailable.</td><td><code>foxglove
episodes edit ep_example --property weather:sun --remove-property
reviewer --applies-to-version 2</code> applies one guarded update and
reports its resulting version.</td></tr>
<tr><td>Historical selection and property inclusion were
unavailable.</td><td><code>foxglove episodes get ep_example --version 2
--include-properties --format json</code> returns the selected snapshot
and properties.</td></tr>
<tr><td>Episode lists could not filter or include custom
properties.</td><td><code>foxglove episodes list --properties-query
'weather:rain' --include-properties</code> filters and returns matching
values; filtering alone does not request inclusion.</td></tr>
<tr><td>Dataset membership lists could not filter or include custom
properties.</td><td><code>foxglove datasets episodes list ds_example
--version 4 --properties-query 'weather:rain'
--include-properties</code> uses the pinned episode snapshots.</td></tr>
<tr><td>Comparisons dropped previous snapshots and omitted changed
counts.</td><td><code>foxglove datasets versions compare ds_example 3 4
--include-properties --format json</code> retains both snapshots and
reports changed membership.</td></tr>
<tr><td>Dataset manifests had no episode custom
properties.</td><td><code>foxglove datasets download ds_example
--version 4 --include-properties</code> includes property objects;
omitting the flag or using <code>--include-properties=false</code> keeps
properties omitted.</td></tr>
</table>

Contract source: [pinned v1 episode schemas and
operations](https://github.com/foxglove/app/blob/aa75bdb8599d2ee795dc83471ae7ee76a040a985/packages/api/src/specs/v1.yaml),
including internal property fields that remain gated and are not yet
exposed in the public API documentation.

API-Sync-Base: unknown (scoped feature comparison, not a repository-wide
sync)

API-Sync-Head: aa75bdb8599d2ee795dc83471ae7ee76a040a985

API-Sync-Scope: episode property creation and single-episode edits;
historical episode reads and version output; property
inclusion/filtering on episode and dataset membership reads;
property-aware comparisons and dataset manifests.

<!--
Humans: remove this when you have proofread and vouched for the content
-->

_[ GENERATED BY AI ]_

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
@brookfxg brookfxg mentioned this pull request Oct 28, 2026
brookfxg added a commit that referenced this pull request Oct 28, 2026
Release v0.22.0.

This release includes:
- Support for episode custom properties (#176)
- Raised minimum `mcap` to 1.6.0 and dropped Python 3.7 support
(`requires-python >= 3.8`) (#172)

Bumped to a minor version because of the Python 3.7 drop and new episode
API surface.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants