| Sprint | Tag | Outcome | Status |
|---|---|---|---|
| S1 Skeleton | v0.4.0-s1-skeleton | Cargo workspace, CLI scaffold, sharded vault, atomic symlink swizzle | ✓ shipped |
| S2 Core port | v0.4.0-s2-core | rusqlite ledger, branch manager, refs, snapshot/revert/checkout/log/diff | ✓ shipped |
| S3 C2PA | v0.4.0-s3-c2pa | Auto-generate manifests on snapshot/revert; verify; inspect; audit (v1) | ✓ shipped |
| S4 Timeline | v0.4.0-s4-timeline | OTIO import/export, domain-split, V1–V10 validator, diff, three-way merge | ✓ shipped |
| S5 Server | v0.4.0-s5-server | JSON-RPC 2.0 + WebSocket + REST blob; bearer-token auth; in-process embed | ✓ shipped |
| S6 Foundation | v0.4.0-s6-foundation | Frontend design tokens, three view shells, TypeScript client | ✓ shipped |
| S6.1 | v0.4.0-s6.1 | Tauri embed, OpenRPC codegen, cursor pagination, Radix wrappers, a11y CI | ✓ shipped |
| S7 Timeline Diff | v0.4.0-s7-timeline-diff | Split-player, synced playback, structured change list, CMX 3600 EDL | ✓ shipped |
| S7.5 AAF | v0.4.0-s7.5-aaf | AAF change-list export (capability-gated via --features aaf-python) | ✓ shipped |
| S8 Views | v0.4.0-s8-views | Branch Graph + Provenance Inspector + Article 50 PDF audit; c2pa.audit/v3 | ✓ shipped |
| S9 Packaging | — | Signed bundles (.dmg/.msi/AppImage), R2 auto-updater, bundle-size CI gates | deferred — budget gate |
| S10 LAN polish | v0.4.0 | Producer-tablet capability gating, mDNS advertise, touch targets, GAV012 final | planned |
| v0.5 Sync | — | gav remote/push/pull, NLE adapters, CAI cert path | post-GA |
Reference
Sprint coverage matrix, architectural decisions that shaped the system, the seven-domain timeline model, server topology, and the v0.4 GA punch list. For diagrams see the Diagrams tab. Press \ to cycle themes, 1/2/3 for tabs.
The ten calls behind the system shape
- Symlinks over copy-on-write (S1). Branch switching is
unlink + symlinkper file inside an atomic temp+rename swizzle. Media bytes don't move; only the pointers flip. Windows works via the developer-mode symlink permission. - rusqlite, not sqlx (S2). The original plan (GAV007 §121, GAV008 §27) called for
sqlxwith compile-time SQL checks. By S2 the team switched torusqlite(sync, bundled) — the engine is single-process, async overhead of sqlx was net negative at this scale, andbundledremoves the libsqlite3 system-library dependency. - OTIO domain-split (S4). Storing one 12 MB OTIO file as a single blob means every grade change rewrites the whole timeline. Splitting into six per-domain JSON files plus a manifest of their hashes gets free dedupe — a colorist's grade change touches
color.jsononly. Three-way merge becomes per-domain; conflict detection becomes per-clip-per-domain. - Hand-rolled OpenRPC, not generated (S5). Neither
schemarsnorokapihas a published crate that ships an end-to-end JSON-RPC + OpenRPC pipeline in 2026. We hand-maintain the OpenRPC document atcrates/gav-server/src/schema/, useschemars 1.0for type-only schema fragments, and rely on a CI drift check (regeneratedmethods.gen.tsmust equal committed) to catch mismatches. - In-process Tauri embed, not sidecar (S6). GAV019 §1.1 #2 chose to spawn
gav-serveron a dedicated tokio task from a Tauri setup hook rather than ship it as anexternalBinsidecar process. Branch checkout is the latency-sensitive operation — cross-process RPC marshalling between webview and sidecar would have measurable cost. - React Flow + dagre, not D3 (S8). Node positioning is dagre's job, edge routing is React Flow's, viewport culling + pan + zoom are free, and the
prefers-reduced-motiongating is a one-line config. Hand-coded D3 would have shipped slower and been harder to ship accessibility coverage against. - Server-side sort + filter for the audit grid (S8). The Provenance Inspector renders blob-level rows at 100k+ scale. Sorting client-side breaks at that volume.
c2pa.audit/v3introduced server-applied sort key (hash / manifested / signature / ai_disclosed) and three filter axes, with cursor formatc2:<sort>:<rank>:<hash>that pins to the active sort — switching mid-stream rejects withInvalidRef. - printpdf for the Article 50 PDF (S8 T2). Pure-Rust, PDF core fonts (Helvetica, no embedding), 8 kB per A4 page — small enough to email. Caveat: the crate uses a random
XObjectIdper document, so byte-identical reproducibility across runs isn't guaranteed (content is identical; bytes differ). Two-run byte-length parity is what we test instead. - Self-signed Ed25519 test cert (S3). Auto-generated under
.gav/c2pa/. Manifests validate asuntrusted; a real CAI-issued cert producestrusted. Ships a working cert path on day one; defers real-cert-loading to v0.5 when a studio actually asks. - CLI parity as a contract (every sprint). Anything the GUI shows, the CLI prints. AAF export →
gav timeline diff --aaf; PDF audit →gav c2pa audit --pdf; capability probe →gav schema. Keeps the product accessible to AI agents and CI pipelines; makes the resilience gate the canonical integration test; prevents UI-only features from drifting away from the data model.
What "domain split" buys you
gav timeline import file.otio writes 6 per-domain JSON workspace files plus a 7th manifest file listing the six blob hashes. Each is snapshotted into the vault and gets a C2PA manifest. Domain JSON edits are versioned independently — colorist edits color.json, sound designer edits audio.json, neither touches the other; gav merges automatically.
- cuts.json — the edit decision list.
CutChange::{Trimmed, Extended, Slipped, Moved, Rippled, Inserted, Removed}using Avid-cultural verbs. - color.json — per-clip
ColorGrade(one version per clip in v0.4; Resolvelocal-versionsdeferred to v0.5). - audio.json — level/pan automation, channel maps, fader writes; the surface a re-recording mixer cares about.
- effects.json — transitions, plug-in effects, speed ramps (annotated with curve type rather than misleading linear pct).
- markers.json — the producer's notes and chapter heads.
- metadata.json — everything else: scene/take, color tags, custom fields. Lossless extras catch-all so OTIO roundtrips bit-for-bit.
- .gav-timeline.json — the manifest blob containing the six blob hashes. This is what gets snapshotted and shared.
Three-way merge runs per-domain with MergeStrategy::Auto (default) / Ours / Theirs. Conflicts are reported with CrossDomainConflict records that name the clip and the colliding domains; gav timeline merge exits 1 on conflict so CI scripts can set -e. The V1–V10 validator catches orphans, sync drift, overlap, out-of-range — exits 0/1/2 for clean/warnings/errors.
What ships, what's untrusted, what's the upgrade path
- Manifest generation is auto on snapshot/revert when
c2pa_auto_generate=truein.gav/config.toml(default true). The signing cert is auto-generated as a self-signed Ed25519 cert under.gav/c2pa/with one-year validity. - Manifests validate as
signed + valid + untrusteduntil a CAI-issued cert is loaded.untrustedis a chain-of-trust statement, not a structural-validity one — the JUMBF and COSE_Sign1 layers are spec-compliant from day one. - Action vocabulary maps to IPTC digital-source-type codes:
humanEdits/algorithmicMedia/trainedAlgorithmicMedia/compositeWithTrainedAlgorithmicMedia. These surface inaurora_audit_summary.ai_disclosedand drive the EU AI Act Article 50 status badge (GREEN/AMBER/RED). - Sidecars live at
.gav/manifests/<aa>/<bb>/<rest>.c2pa— mirrors the vault's sharded layout. Idempotent inserts viaON CONFLICT … DO UPDATE; same blob can be re-manifested without duplicate rows. - Server-side audit (
c2pa.audit/v3) applies sort + filter via named-param SQL only. SQL injection surface reviewed (S8-R9): enum values map to&'static strslices; no user string interpolates. The cursor formatc2:<sort>:<rank>:<hash>pins to the active sort; switching mid-stream returnsInvalidRefso the client refetches from page 0. - PDF rendering uses
printpdf 0.9.1with PDF core fonts (Helvetica, no embedding) for byte-stable output across platforms. Cover page maps to Article 50 disclosure categories; paginated asset table with consistent column headers;--article-50-onlyfilter trims the report to assets requiring disclosure. - The CAI upgrade path is a one-page section in GAV012 — load the studio's CAI-issued cert chain into
.gav/c2pa/cert.pem, manifests now validate astrusted. Currently documented but not exercised end-to-end; a real studio's first install will surface whatever's missing.
How gav serve fits
- One axum 0.8 router serving
POST /rpc(JSON-RPC 2.0, 24 methods),GET /ws(WebSocket event bus), andGET /blob/<hash>(REST blob stream with C2PA verify-default). - Bearer-token auth. OS keychain (
keyring3.x) with.gav/server/tokenfile fallback. Default bind is loopback127.0.0.1:7777. Non-loopback bind requires--cors-originAND a token — the CLI refuses to start otherwise. - In-process embed.
Server::start_in_process(...)exposes the same router on a dedicated thread + tokio runtime so Tauri can embed without Windows event-loop conflicts. The Tauri app gets the full RPC surface without spawning a sidecar process. - Capability gating (S10 T1). A new
server.capabilitiesRPC will return the set of methods the current token can call; producer-tablet read-tokens will hide write buttons in the UI. Currently planned, not shipped. - OpenRPC drift CI is clean. Hand-maintained OpenRPC document at
crates/gav-server/src/schema/; regeneratedmethods.gen.tsinpackages/api-clientmust equal committed or CI fails. - The CLI never depends on the server.
gav-clilinksgav-coredirectly. No daemon required for any CLI op. The resilience gate (tests/cli/full_workflow.sh) runs end-to-end without ever starting the server.
- Capability atom + producer-tablet capability gating. New
server.capabilitiesRPC; ~15-component audit; read-token tokens hide write buttons. The producer-with-iPad scenario lights up end-to-end. - Touch-target spacing.
@media (pointer: coarse)→ 44×44 px button minimum, 36 px row height. Frame.io's actual moat is iPad UX; this is the answer. - mDNS advertise.
gav serve --mdnsmakes the server findable as_gav._tcp.localon the LAN. Producer's tablet finds the editor's machine on the next-door studio Wi-Fi. - CLAUDE.md S10-line correction + GAV012 finalization. Deployment-mode walkthroughs with screenshots; CAI procurement note.
- Repo-commands.html refresh + RELEASE_NOTES.md + full README rewrite. The README still says "S6.1 shipped, S7 in progress" because nothing forced a rewrite. S10 T5 forces it.
- GAV027 sprint report + tag
v0.4.0. No sprint suffix — GA.
Honest list of unresolved questions
- S9 cert + R2 + secrets decision. Plumbing ready; certificates and DNS are the operational gate. Estimated half-day of work once the budget call gets made — ~$219/yr (Apple Developer ID + Azure Trusted Signing).
- CAI cert procurement path. Documented in GAV012 but not exercised end-to-end. A real studio's first install will surface whatever's missing in the procurement walk.
- NLE auto-snapshot hooks. GAV017 specifies the
NleAdaptertrait; no NLE adapter crates exist in the workspace (thegav-nle-*placeholder feature flags ingav-cliare stubs — flagged in GAV028 §M6). Adoption depends on at least one of Resolve / Premiere / FCP / Avid having a transparent auto-snapshot hook by v0.5. - Sync wire protocol (v0.5). Three candidates per GAV026 §10: custom JSON-RPC, git smart-HTTP, WebSocket delta. The right answer is partly determined by whether the eventual SaaS mode wants to ride the same protocol.
- Production data scale. Vault tests through S8 use synthesized fixtures. A real studio with 50 TB of media and 18 months of branches will reveal the next-order performance constraints. The Trust Ladder + sharded vault was designed for that scale; testing it is empirical, not architectural.
- i18n. English-only is fine for v0.4 (post-production audience is ~95% English-readable). v0.5 wires it; v1.0 might localize to JP/KR/FR/DE based on actual installs.
- Resolve grade-versions (≤6 per clip). The flat
ColorGrademodel in v0.4 doesn't capture Resolve's local-versions feature. AColorGrade::versions: Vec<NodeGraph>extension is a clean v0.5 timeline-model addition. - Playwright coverage for S8. Plan called for 6 specs; 0 landed in the compressed S8 timeline. The data path is verified via typecheck + build + resilience gate; full E2E coverage is an S8.x fast-follow alongside the 100k-row perf gate.
Planning docs, sprint reports, audits, and design briefs maintained alongside the source tree under docs/gav/. Not currently published; listed here so stakeholders know what exists.
| Doc | Title | Type |
|---|---|---|
| GAV007 | v0.4 Architecture | Plan |
| GAV008 | Rust Core Migration | Plan |
| GAV009 | Timeline Domain Model | Plan |
| GAV010 | Frontend Design System | Plan |
| GAV011 | API Reference | Reference |
| GAV012 | Deployment Modes | Plan |
| GAV013 | NLE Adapter Cookbook | Plan |
| GAV014 | CLI-First Resilience | Plan |
| GAV015 | S2 Core Port Plan | Plan |
| GAV016 | S3 C2PA Plan | Plan |
| GAV017 | S4 Timeline Plane Plan | Plan |
| GAV018 | S5 Server Plan | Plan |
| GAV019 | S6+ Frontend Plan | Plan |
| GAV020 | S6 W11-W12 Sprint Report | Report |
| GAV021 | S6.1 Sprint Report | Report |
| GAV022 | S7 Sprint Report | Report |
| GAV023 | S7.5 AAF Sprint Report | Report |
| GAV024 | S8 Sprint Report | Report |
| GAV025 | S9 Prep Notes | Prep |
| GAV026 | S10 Plan | Plan |
| GAV028 | Post-S8 Repo Audit | Audit |
| GAV029 | Product Design Brief | Brief |