Conversation
File > Push Notes to Tracker... sends this source comments to ftrack or ShotGrid as review notes. Drawings are not pushed: a tracker note is words, and a scribble without the frame under it says nothing. The annotated frames go up via the PDF report or the image export instead. The ftrack field mapping was checked against a live ftrack instance Note schema, not inferred from the docs, and two things it revealed would otherwise have been wrong: - frame_number is a NATIVE integer field on Note. ftrack anchors notes to a frame itself, so FrameDeck per-frame comments map straight onto it. The obvious guess, encoding the frame into the note text, would have thrown away the one thing that makes the note reviewable in place. - user_id is REQUIRED. A note cannot be posted anonymously, so the author is resolved from the session up front. Failing there beats a server-side rejection with half the notes already in flight. Resolved comments arrive as completed to-dos (is_todo) rather than as open notes an artist has to triage again, and FrameDeck comment id is stamped into Note.metadata so re-pushing a shot updates the existing notes instead of littering the tracker with duplicates. tests/data/ftrack_note_schema.json is a snapshot of that live schema, and a conformance test pins every field we send against it, so an invented field name can never reach a server. ShotGrid is NOT validated against a live site and says so in its module docstring. Its Note entity has no frame field at all (frame-accurate notes live on Version annotations, a much larger integration), so the frame is carried in the note subject and body where a human will actually read it. Both trackers take an injected session, so the mapping is tested against a fake client with no server, no credentials and no network. Credentials are read from the standard environment variables by the APIs themselves; FrameDeck never stores or handles them. 18 tests, 256 on the branch. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TexnzYbmCjjTDB8zzZuUPb
reviewapp has a working, production-proven ftrack push. Reading it against this one found a real bug that mock tests could never catch. In ftrack, is_todo and completion are SEPARATE concerns: is_todo says a note is actionable, completed_at and completed_by_id say it has been done. reviewapp sets is_todo True on every note it pushes, and that is right. This code mapped is_todo to the reviewer done flag, which is backwards and quietly so: - an OPEN comment became is_todo False, a plain note nobody is asked to action - a RESOLVED comment became is_todo True with no completion, landing in the artist queue as fresh, uncompleted work So every note the supervisor had already closed would have arrived as a new task. Now every note is a to-do, and a resolved one also carries completed_at and completed_by_id. Re-pushing after resolving closes the ftrack to-do rather than merely rewording it. Also follows reviewapp in leading the note body with the clip and frame: [KP_010_020] F0042 00:00:01:18 - soften this frame_number is still set, which reviewapp does not do -- it is a real field on the live schema and it is what lets ftrack anchor a note to a frame in its player. But it is not relied on: anywhere the field is not surfaced (a notes list, an email digest), the body still says which frame the note is about. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TexnzYbmCjjTDB8zzZuUPb
|
Updated after diffing against reviewapp's production-proven ftrack provider. It caught a real bug that no mock test could have.
|
| FrameDeck comment | what it would have become in ftrack |
|---|---|
| open | is_todo=False — a plain comment nobody is asked to action |
| resolved | is_todo=True, never completed — an open to-do in the artist's queue |
So every note the supervisor had already closed would have arrived at the artist as fresh work, while the genuinely open ones sat there as passive comments. It would have passed review, passed the mocks, and only surfaced as artists asking why their queue was full of things already fixed.
Now: every note is a to-do, and a resolved one also carries completed_at + completed_by_id. Re-pushing after resolving closes the ftrack to-do rather than just rewording it (test_resolving_a_note_and_repushing_closes_the_ftrack_todo).
Note body now leads with clip and frame
Following reviewapp's proven format:
[KP_010_020] F0042 00:00:01:18 - soften this edge
frame_number is still set — reviewapp doesn't set it, but it's a real field on the live schema and it's what lets ftrack anchor a note to a frame in its player. Crucially it is no longer relied on: anywhere that field isn't surfaced (a notes list, an email digest), the body still says which frame the note is about. Belt and braces rather than a bet on an unproven field.
Remaining difference from reviewapp, deliberately
- Author field. reviewapp sets
author_id; this setsuser_id, which is the field the live schema actually declares (and declares as required). Both evidently work — reviewapp is in production — so this is the schema-conformant spelling of the same thing. Worth a second pair of eyes. - Thumbnail attachment. reviewapp uploads the rendered annotated frame as a
FileComponentand links it viaNoteComponent, so the artist sees the drawing next to the note. This PR doesn't — it's a genuinely valuable feature and a self-contained follow-up, but it's a multipart-upload pipeline and I didn't want to bundle it into a note-push PR. Happy to do it next if wanted.
Verification status, restated honestly
- ftrack field mapping: verified against a live instance's schema, and now cross-checked against a working production implementation.
- ftrack round-trip: still not run. No note has been created on a real tracker. Someone should push to a throwaway AssetVersion once before this is trusted.
- ShotGrid: mock-tested only, unvalidated.
257 tests, compile clean.
File > Push Notes to Tracker...sends this source's comments to ftrack or ShotGrid as review notes.Drawings are not pushed — a tracker note is words, and a scribble without the frame under it says nothing. The annotated frames go up via the PDF report (#26) or the image export instead.
The ftrack mapping was checked against a live instance, not guessed
I pulled the real
Noteschema from a live ftrack instance rather than inferring it from the docs, and two things it revealed would otherwise have been wrong:frame_numberis a native integer field onNote. ftrack anchors notes to a frame itself. FrameDeck's per-frame comments therefore map straight onto it. The obvious guess — encoding the frame into the note text — would have thrown away the one thing that makes the note reviewable in place, and it would have looked like it worked.user_idis REQUIRED. A note cannot be posted anonymously. The author is now resolved from the session up front, so a bad configuration fails immediately rather than being rejected server-side with half the notes already in flight.tests/data/ftrack_note_schema.jsonis a snapshot of that live schema, andtest_every_ftrack_field_we_send_exists_on_the_live_schemapins every field we send against it. An invented field name can no longer reach a server.Other mappings that fall out of the real schema:
contentframe_number(native)is_todo— arrives as a completed to-do, not an open note an artist has to triage againmetadata— so re-pushing a shot updates existing notes instead of littering the tracker with duplicatesShotGrid is NOT validated against a live site
Stated plainly in its module docstring, because the difference matters. It follows the documented
shotgun_api3Noteentity, but nobody has run it against a real ShotGrid.The known structural difference: ShotGrid's
Notehas no frame field at all. Frame-accurate notes there live on Version annotations, which is a much larger integration. So the frame is carried in the note subject and body, where a human will actually read it. If you want true frame-anchored ShotGrid notes, that's a separate and considerably bigger piece of work.Testing without a server
Both trackers take an injected session, so the mapping is exercised against a fake client — no server, no credentials, no network. 18 tests cover the payloads, the required-author failure, duplicate suppression on re-push, an edited comment updating in place, a rejected commit rolling the session back (a dirty session would poison the next push), and "push nothing" not touching the server at all.
Credentials are read from the standard environment variables by the APIs themselves (
FTRACK_SERVER/FTRACK_API_USER/FTRACK_API_KEY,SHOTGRID_SITE/SHOTGRID_SCRIPT_NAME/SHOTGRID_API_KEY). FrameDeck never stores or handles them, and the dialog never asks for them — it only asks what the tracker cannot know: which entity the notes belong to.ftrack_apiandshotgun_api3are imported lazily and are optional: FrameDeck starts fine without either.Verification status — read this before merging
256 tests on the branch, compile clean. Branches off current
main.