Skip to content

Correct the documented on-disk annotation file format - #461

Open
gbeane wants to merge 2 commits into
mainfrom
claude/quality-2026-09-09
Open

Correct the documented on-disk annotation file format#461
gbeane wants to merge 2 commits into
mainfrom
claude/quality-2026-09-09

Conversation

@gbeane

@gbeane gbeane commented Sep 9, 2026

Copy link
Copy Markdown
Collaborator

Reasoning

I went looking for a bug first and did not find one I was confident in, so I picked the next
category: misleading documentation. The docstring on
VideoLabels.as_dict
is the only place in the tree that documents the layout of a project's
jabs/annotations/<video>.json file, so anyone reading a JABS annotation file from an external
tool ends up here. It was wrong in four ways:

  1. A key that does not exist. The example showed a timeline annotation's optional identity
    field as "animal_id": 0. The actual key written by
    TimelineAnnotations.serialize
    is "identity". animal_id appears nowhere else in src/ or packages/ -- a consumer
    following the docstring would silently never find the identity.
  2. The external_identities example was malformed and backwards. It read
    "external_identities: { "jabs identity", 1234, } -- an unterminated key and a comma instead
    of a colon -- and implied the mapping went from a name to a number. The code writes
    {str(jabs_identity_index): external_identity}.
  3. version was undocumented. as_dict has written a "version" key
    (SERIALIZED_VERSION) since it was added, but the example never showed it.
  4. labels vs unfragmented_labels was unexplained. Both were shown with byte-identical
    contents, which reads as pointless duplication. In fact labels is masked by
    pose.identity_mask() (blocks split where the identity is absent from the pose file) while
    unfragmented_labels is what the user actually labeled, and load() prefers
    unfragmented_labels. That distinction is the single most important thing about this format
    and it was missing.

This is safe because it is comments only: no statement, expression, signature, or default was
touched, so behavior is net-zero by construction. Nothing in the tree parses these docstrings.

Change

Logic changes

None -- every edit is inside a docstring.

Documentation changes

  • src/jabs/project/video_labels.py -- rewrote the as_dict docstring. It now has proper
    Args/Returns sections, documents each top-level key (including version), spells out the
    labels / unfragmented_labels difference and which one load() prefers, notes that
    external_identities and annotations are only present conditionally, points at
    TimelineAnnotations.serialize for annotation entry fields, and carries a valid JSON example
    with "identity" instead of "animal_id".
  • src/jabs/project/timeline_annotations.py -- documented the serialized fields of one
    annotation (start, end, tag, color, optional description, optional identity) on
    serialize(), where they are produced, and noted that the derived display_identity is not
    serialized because load() recomputes it.
  • packages/jabs-core/src/jabs/core/abstract/pose_est.py -- corrected the
    external_identities entry in the PoseEstimation class docstring: the property is annotated
    and populated as list[str] | None, not list[int] | None (the v4+ readers stringify the raw
    ids).

No mechanical/import churn in this PR.

Verification

  • uv run --only-group lint ruff check -- all checks passed
  • uv run --only-group lint ruff format --check -- 460 files already formatted
  • uv run pytest -- 879 passed, 254 skipped
  • uv run pytest packages/jabs-core/tests -- 88 passed

🤖 Generated with Claude Code


Generated by Claude Code

The docstring on VideoLabels.as_dict is the reference for the on-disk
jabs/annotations/<video>.json format, and it was wrong in several ways:

- the optional identity field of a timeline annotation was documented as
  "animal_id", a key that appears nowhere in the code
- the "external_identities" example was malformed and had the mapping
  backwards
- the "version" key that as_dict always writes was undocumented
- "labels" and "unfragmented_labels" were shown with identical contents
  and no explanation of the difference between them

Rewrite it to document each key, note that load() prefers
"unfragmented_labels", and give a valid example. Document the fields of a
serialized annotation in TimelineAnnotations.serialize, where they are
produced, and correct the external_identities type in the PoseEstimation
class docstring (list[str], not list[int]).

Documentation only, no behavior change.
@gbeane
gbeane requested a lite review from Copilot September 9, 2026 05:13
@gbeane gbeane self-assigned this Sep 9, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟢 Approval recommended

Documentation-only updates align with current serialization behavior, and the remaining feedback is a minor clarity nit.

Pull request overview

This PR corrects and clarifies the documented on-disk JSON format for JABS per-video annotation files (jabs/annotations/<video>.json) by updating the relevant docstrings to match what the code actually serializes/deserializes.

Changes:

  • Rewrites VideoLabels.as_dict() docstring to accurately document top-level keys (including version), fix the identity key name (identity), and explain labels vs unfragmented_labels.
  • Documents the serialized fields produced by TimelineAnnotations.serialize() and consumed by TimelineAnnotations.load().
  • Fixes the PoseEstimation docstring type/meaning of external_identities to reflect list[str] | None.
File summaries
File Description
src/jabs/project/video_labels.py Updates as_dict() docstring to match the real JSON annotation file structure and key semantics.
src/jabs/project/timeline_annotations.py Documents the serialized annotation entry fields and clarifies what is (and isn’t) persisted.
packages/jabs-core/src/jabs/core/abstract/pose_est.py Corrects external_identities docstring to `list[str]
Review details
  • Files reviewed: 3/3 changed files
  • Comments generated: 1
  • Review effort level: Lite

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

Comment thread src/jabs/project/video_labels.py
Addresses review feedback: the example in VideoLabels.as_dict is the
serialized JSON file, so its `true` is JSON rather than a Python literal.
Say so explicitly instead of leaving the reader to infer it.
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