AI Video Summarization

ClipSpark

Spark Insights from Every Video

ClipSpark uses AI to analyze long-form video and produce accurate, timestamped captions, concise summaries, and one-click highlight clips. It helps educators, podcasters, and knowledge workers who repurpose recordings by pinpointing context-rich moments. ClipSpark cuts scrubbing and manual editing time by 70%, triples shareable output, and saves users about six hours weekly.

Subscribe to get amazing product ideas like this one delivered daily to your inbox!

ClipSpark

Product Details

Explore this AI-generated product idea in detail. Each aspect has been thoughtfully created to inspire your next venture.

Vision & Mission

Vision
Enable educators, creators, and knowledge teams to instantly extract and share concise, actionable video insights, reclaiming hours for higher-impact work.
Long Term Goal
Within 3 years, enable 10,000 educators, podcasters, and teams to save one million hours annually by instantly extracting, captioning, and sharing searchable video highlights.
Impact
For educators, podcasters, and knowledge workers, ClipSpark reduces scrubbing and manual editing time by 70%, triples shareable clip output, and delivers >95% caption accuracy, saving an average user 6 hours weekly and enabling faster, searchable access to key video moments.

Problem & Solution

Problem Statement
Educators, podcasters, and knowledge workers waste hours scrubbing long recordings to find, caption, and edit shareable moments because auto-captions are error-prone, manual clipping is slow, and summaries lack accurate, timestamped context.
Solution Overview
ClipSpark analyzes long-form video with AI to automatically locate and extract context-rich moments. It produces accurate, timestamped captions and topic-based jump links with one-click exportable highlight clips, eliminating hours of manual scrubbing and error-prone caption fixes.

Details & Audience

Description
ClipSpark generates accurate, timestamped captions, concise summaries, and ready-to-share highlight clips from long-form video. It serves educators, podcasters, knowledge workers, and creators who need fast access to key moments. ClipSpark cuts scrubbing and manual editing time by 70%, delivering usable clips and searchable summaries in minutes. Topic-based jump links let users jump directly to context-rich moments.
Target Audience
Educators, podcasters, and knowledge workers (25–50) needing fast, accurate highlights who frequently repurpose clips
Inspiration
While prepping a workshop, I scrubbed through a 90-minute lecture for a 90-second demo, staring at pixelated waveform markers and mangled auto-captions that turned PCR into paper. Each manual cut ruined the demo’s rhythm. Frustration flipped to clarity: an assistant that pinpoints moments, repairs technical captions, and exports polished, timestamped clips—so educators and creators can teach, not tinker.

User Personas

Detailed profiles of the target users who would benefit most from this product.

E

Earnings Extractor Evan

- Age: 29–41; Equity Research Analyst at buy-side fund. - Located in New York or London; travels for conferences quarterly. - CFA charterholder; economics or finance degree; 6–12 years experience. - Works on fast-paced desks; handles 10–20 calls weekly.

Background

Cut his teeth summarizing calls manually at a boutique shop. Missed trades from slow post-call synthesis pushed him to automate extraction and standardize notes.

Needs & Pain Points

Needs

1. Accurate, timestamped earnings-call summaries. 2. Fast highlight clips for PM briefings. 3. Speaker labels for multi-executive calls.

Pain Points

1. Crosstalk wrecks transcripts and attribution. 2. Manual scrubbing wastes the post-call window. 3. Generic AI mangles finance jargon.

Psychographics

- Competes on speed-to-insight, not page length. - Trusts data, distrusts marketing spin. - Obsessive about security for sensitive information. - Precision fanatic about quotes and context.

Channels

1. Bloomberg Terminal — news 2. LinkedIn — finance peers 3. X — earnings chatter 4. Seeking Alpha — transcripts 5. Slack — research team

C

Case-Prep Casey

- Age: 28–48; Litigation Associate or Senior Paralegal. - AmLaw 100 or mid-size firm; case teams 5–20. - JD or paralegal certificate; eDiscovery tools experience. - US-based; frequent remote depositions across time zones.

Background

Cut thousands of pages of testimony into trial binders by hand. Missed nuances and late nights convinced Casey to standardize timestamped clips and searchable transcripts.

Needs & Pain Points

Needs

1. Courtroom-ready timestamps and quotable excerpts. 2. Secure handling preserving privilege. 3. Diarization across multiple deponents.

Pain Points

1. Manual review devours billable hours. 2. Inaccurate transcripts miss crucial qualifiers. 3. Cloud tools raise privilege concerns.

Psychographics

- Rigor over rhetoric, evidence rules everything. - Risk-averse, compliance-first, cautious technology adopter. - Detail-obsessed, perfectionist about exact phrasing. - Loyal once trust and audits are proven.

Channels

1. Westlaw — research 2. LinkedIn — legal peers 3. ILTA Connect — forums 4. Relativity Community — eDiscovery 5. Outlook — firm email

E

Event Clip Crafter Cara

- Age: 27–39; Field/Event Marketing Manager. - B2B SaaS; 100–1000 employees; pipeline targets. - US/EU-based; hybrid; travels during event season. - Intermediate video skills; owns webinar platforms.

Background

Started as social manager, self-taught editing to keep up with demand. Bottlenecked by post-production queues, she now prioritizes auto-highlights and on-brand captions.

Needs & Pain Points

Needs

1. One-click topic-based highlight reels. 2. Auto-styled captions and aspect ratios. 3. Searchable timestamps for session pages.

Pain Points

1. Hours lost hunting marketable moments. 2. Editor backlogs miss promotion windows. 3. Inconsistent captions hurt engagement.

Psychographics

- Growth-driven, relentlessly obsessed with repurposing. - Visual storyteller under tight deadlines. - Pragmatic; favors done over perfect. - Loves data-backed, test-and-learn creative decisions.

Channels

1. LinkedIn — B2B reach 2. YouTube — archives 3. HubSpot — campaigns 4. Slack — marketing team 5. TikTok — teasers

S

Support Snippet Sam

- Age: 31–45; Support Enablement or QA Manager. - Contact center 50–300 agents; omnichannel. - Global team; heavy Zoom and telephony recordings. - Tools: Zendesk, Salesforce Service, LMS.

Background

Rose from top agent to coach, building playbooks from countless calls. Drowning in recordings, Sam needs searchable highlights and reliable captions across accents.

Needs & Pain Points

Needs

1. Surface best-resolution clips by issue. 2. Auto-tag patterns and sentiments. 3. Accurate captions across accents.

Pain Points

1. Triaging thousands of calls wastes hours. 2. Hard to find coachable moments fast. 3. Accent-heavy audio breaks transcripts.

Psychographics

- Customer empathy, outcome over script. - Coach through concrete, real examples. - Data-led; tracks trend shifts weekly. - Pragmatic about tooling and ROI.

Channels

1. Zendesk — workflows 2. Slack — internal comms 3. Zoom — recordings 4. LinkedIn — support leaders 5. Guru — knowledge base

C

Civic Summarizer Sofia

- Age: 36–55; City Clerk or Communications Officer. - Municipality population 50k–500k; public sector. - Owns agendas, minutes, accessibility compliance. - Limited staff; legacy systems; high public scrutiny.

Background

Years of late-night minute drafting and ADA audits shaped meticulous habits. Sofia seeks tools that cut turnaround while improving transparency.

Needs & Pain Points

Needs

1. WCAG-compliant, timestamped captions. 2. Topic-indexed summaries for minutes. 3. Searchable archives for public requests.

Pain Points

1. Overnight minute drafting after long meetings. 2. Caption accuracy scrutinized by residents. 3. Clunky legacy software slows publishing.

Psychographics

- Transparency evangelist, proudly serving residents. - Compliance-first, zero tolerance for errors. - Detail-oriented under constant political pressure. - Patient, process-driven, consensus-building team collaborator.

Channels

1. Granicus — agendas 2. YouTube — broadcasts 3. Facebook — community updates 4. GovDelivery — email alerts 5. Microsoft Teams — internal

H

Hiring Highlights Hayden

- Age: 27–40; Senior Recruiter or Talent Partner. - Tech startups 50–300 employees; remote-first. - Heavy Zoom usage; Greenhouse or Lever ATS. - Coordinates across time zones with busy panels.

Background

Began with handwritten notes and memory-driven debriefs. After misaligned hires, Hayden adopted rigorous, timestamped evidence and structured scorecards.

Needs & Pain Points

Needs

1. Timestamped clips aligned to competencies. 2. Summaries mapped to scorecards. 3. Easy redaction and expiring links.

Pain Points

1. Panelists won’t watch full recordings. 2. Notes miss nuance and examples. 3. Privacy risk sharing candidate videos.

Psychographics

- Speed-to-offer mindset without sacrificing rigor. - Collaboration culture that reduces interview bias. - Values candor, context, and signal. - Tooling must vanish into workflows.

Channels

1. Greenhouse — ATS 2. LinkedIn — sourcing 3. Zoom — interviews 4. Slack — hiring channels 5. Notion — scorecards

Product Features

Key capabilities that make this product valuable to its target users.

Policy Blueprints

Jumpstart compliance with prebuilt templates for retention, export controls, and watermarking (SOC 2, HIPAA, FINRA, GDPR). Apply policies at org, team, or project scope, simulate impact before rollout, and fix gaps with guided suggestions—reducing setup time and audit risk.

Requirements

Policy Enforcement Runtime
"As a security and compliance admin, I want policies to be enforced automatically across all video workflows so that no user action can violate our compliance requirements."
Description

Real-time enforcement service integrated into ClipSpark’s upload, processing, sharing, and export pipelines to apply retention, export control, and watermarking rules. Enforces automatic retention/expiration, legal holds, export restrictions (by role, domain, geo, and IP), and dynamic watermark overlays on playback and exported assets, including highlight clips and captions. Provides deterministic decisioning with clear failure messages, logs every enforcement action with immutable audit trails, and exposes APIs and webhooks for downstream systems.

Acceptance Criteria
Real-Time Enforcement Across Pipelines
Given an upload, processing, sharing, or export request with actor, asset, and context (role, domain, geo, IP, scope) When the Policy Enforcement Runtime evaluates applicable policies Then a decision and reason_code are returned within p95 150ms and p99 300ms, and the pipeline proceeds only on allow Given identical inputs (actor, asset metadata, policies, and evaluation time) When evaluated repeatedly Then the decision and reason_code are deterministic and identical Given a denied decision When the pipeline step is invoked Then no side effects occur (no asset written, no share created, no job dispatched) and a 4xx error with human_readable_message and reason_code is returned Given a transient evaluator error When retries are exhausted (max 3 over 2s) Then the request fails with reason_code=POLICY_UNAVAILABLE and no side effects, and the caller receives a correlation_id Given policies defined at org, team, and project scopes When conflicts exist Then the resolution order is project > team > org unless a higher-scope policy is marked non_overridable, in which case it prevails
Retention and Expiration Enforcement
Given an asset under a retention policy of N days and not on legal hold When asset_age >= N days at evaluation time Then read, share, and export are denied with reason_code=RETENTION_EXPIRED Given an expired asset not on legal hold When the nightly purge job runs Then the asset, derived highlight clips, captions, and exports are deleted within 24h, and references are tombstoned Given retention is extended When the policy is updated Then the new expiration applies immediately; if already expired but not purged, access remains denied and purge proceeds Given retention is shortened When the new expiration would be earlier than now Then access is denied immediately and purge is scheduled; no data is deleted synchronously
Legal Hold Override of Retention
Given an asset on legal hold When its retention period elapses Then the asset and derivatives are not purged and remain accessible to authorized roles; exports still respect export control policies Given any delete or purge attempt on a held asset When invoked Then it is blocked with reason_code=LEGAL_HOLD and HTTP 423 Given a legal hold removal by an authorized role When removed Then expiration is recalculated using the current retention policy and purge eligibility is evaluated within 1h Given a legal hold removal by an unauthorized actor When attempted Then it is denied with reason_code=INSUFFICIENT_PERMISSIONS and no state change occurs
Export Controls by Role, Domain, Geo, and IP
Given a user without an allowed role per policy When requesting export or external share Then it is denied with reason_code=ROLE_RESTRICTED Given recipient emails outside allowed domains When creating a share Then it is denied with reason_code=DOMAIN_RESTRICTED Given a request originating from a country or IP outside allowed ranges When exporting or downloading Then it is denied with reason_code=GEO_IP_RESTRICTED Given a highlight clip or caption export When evaluated Then the same export control rules apply identically as the parent asset Given an allowed request When export proceeds Then a decision record with allow and policy_ids is written before any file is generated
Dynamic Watermark on Playback and Exports (Video, Highlights, Captions)
Given playback under a watermark policy requiring user_id, timestamp, and request_ip overlays When streaming starts Then the watermark is visibly rendered on video frames in at least two non-static positions per minute and cannot be disabled via client parameters Given an export under a watermark policy When the file is generated Then the watermark is burned into the video and any highlight clips; removal by simple re-encode does not reduce visibility below SSIM 0.98 Given captions are exported under a watermark policy When the .srt or .vtt file is produced Then a non-intrusive watermark footer containing watermark_id and export_timestamp is appended without altering existing cue timings Given watermark rendering When measured Then added playback start latency is p95 <= 50ms and p99 <= 100ms
Immutable Audit Logging of Enforcement Actions
Given any allow or deny decision When evaluated Then an audit record is written with fields: request_id, asset_id, actor_id, scope, policy_ids, decision, reason_code, timestamp, and context (role, domain, geo, ip) before side effects Given audit storage When records are appended Then each record’s hash links to the previous (hash chain) and the chain verifies end-to-end daily with zero integrity failures Given a request_id When querying the audit API Then the record is retrievable within 2 seconds and includes a verifiable hash Given a tamper attempt on an audit record When mutation or deletion is attempted Then it is rejected and a SECURITY event is logged with reason_code=AUDIT_IMMUTABLE
Enforcement APIs and Webhooks for Downstream Systems
Given the Enforcement Decisions API When called with valid OAuth2 client credentials and an idempotency_key Then it returns 200 with decision, reason_code, policy_ids, and ttl in p95 <= 150ms Given an enforcement event (allow or deny) When committed Then a webhook is delivered within 1s with an X-ClipSpark-Signature (HMAC-SHA256) and timestamp header; failures retry up to 8 attempts over 15 minutes Given webhook retries are exhausted without a 2xx When the backoff completes Then the event is placed in a dead-letter queue and is queryable via API Given a duplicate API request with the same idempotency_key within 24h When received Then the original response is returned and no duplicate decision record is created
Scope-aware Policy Application
"As an org admin, I want to apply policies at the appropriate scope with predictable inheritance so that teams get the right controls without duplicating configuration."
Description

Hierarchical policy assignment with organization, team, and project scopes supporting inheritance, overrides, and time-bound exceptions. Includes an effective policy viewer that resolves conflicts and previews the resulting controls for a given asset or user. Supports bulk application via UI and API, conflict detection with suggested resolutions, and full audit trails for assignments and changes.

Acceptance Criteria
Hierarchical Inheritance and Override Across Org, Team, Project
- Given an organization with Team A and Project X under Team A and an org-level retention policy P1, when a team-level retention policy P2 is assigned to Team A, then Project X inherits P2 unless a project-level override exists. - Given Project X has a project-level policy P3, when P2 is removed from Team A, then the effective retention for Project X remains P3 and other Team A projects inherit P1. - When the org-level policy P1 is updated to P4, then Project X’s effective policy remains P3 while teams without overrides inherit P4. - Precedence order is enforced for all controls: project > team > org. - Assigning a policy at a higher scope does not create implicit persistent assignments on child nodes; only effective evaluation changes. - The Effective Policy API/viewer reports the final policy ID and its source scope consistent with the above rules.
Time-Bound Exception Scheduling and Reversion
- Given Team A has retention R3 (3 years), when a time-bound exception R30 (30 days) is scheduled from 2025-10-01T00:00:00Z to 2025-10-31T23:59:59Z, then the effective retention for Team A’s assets is 30 days only within that window. - At 2025-11-01T00:00:00Z, the effective retention automatically reverts to 3 years without manual action. - Overlapping exceptions on the same scope/control are rejected at save time with HTTP 409 (API) and an inline validation error (UI) describing the overlap. - Exceptions are stored in UTC; the UI displays creator’s local time with UTC reference. - Cancelling an exception before its start results in no policy change and creates an audit record with reason.
Effective Policy Viewer — Resolution and As-Of Preview
- Given a selected asset or user, when opening the Effective Policy Viewer, then it displays the computed effective controls (retention, export controls, watermarking), contributing assignments with scopes, and the resolution rationale. - Conflicts are highlighted with badges/tooltips that explain the winning source via precedence and any active time-bound exception. - The viewer supports an "as-of" datetime parameter; when provided, it computes effective controls for that timestamp. - For entities with ≤10 contributing assignments, the viewer renders within 2 seconds at p95. - The viewer shows the next scheduled effective change (from time-bound exceptions) if it occurs within the next 90 days.
Conflict Detection with Guided Suggestions
- When saving an assignment that is less restrictive than an ancestor for the same control, the system detects a conflict pre-commit and presents a structured conflict object (UI modal; API 409) listing conflicting sources. - Suggested resolutions include: (a) apply most restrictive value at current scope, (b) add explicit override at higher scope, (c) convert to a time-bound exception, or (d) cancel change. - Selecting a suggestion applies changes atomically and revalidates so that no conflicts remain. - After applying a suggestion, the effective policy matches the chosen resolution across affected entities.
Bulk Policy Application via UI — Scale and Reliability
- Given a user selects N targets (teams/projects/assets) where 1 ≤ N ≤ 10,000 and chooses a policy assignment, then a dry-run preview lists impacted counts by scope and highlights potential conflicts. - Upon confirmation, an asynchronous job is created; a progress view shows total processed, successes, and per-target failures with error codes and retry counts. - The job achieves p95 completion for 10,000 targets within 5 minutes; failed targets are retried automatically up to 3 times unless errors are non-retryable. - Re-running the same bulk action with identical inputs is idempotent and results in no duplicate assignments.
Bulk Policy Application via API — Idempotent, Async, Atomic
- POST /policies/bulk-assign accepts up to 10,000 target IDs, scope, policy_id, controls, mode ∈ {all_or_nothing,best_effort}, and an Idempotency-Key; returns 202 with job_id. - GET /policies/bulk-assign/{job_id} returns overall status ∈ {queued,running,succeeded,failed,partial}, per-target results, and conflict summaries until terminal. - With mode=all_or_nothing, any single failure aborts and no targets are modified; with mode=best_effort, successful targets commit and failures are reported. - Requests above 5 req/s per org are throttled with 429 and a Retry-After header. - Replaying the same Idempotency-Key within 24 hours returns the original job_id and produces no duplicate effects.
End-to-End Audit Trail for Assignments and Changes
- Every create/update/delete of assignments, overrides, and exceptions writes an immutable audit record capturing: timestamp (UTC), actor (user/service), auth method, scope, target(s), control(s), before/after values, reason/comment, source (UI/API), IP, correlation_id/job_id. - Audit records are queryable in the UI and via GET /audit with filters (date range, actor, scope, target, control, policy_id), are paginated, and can be exported as CSV or JSON. - Audit records are tamper-evident via hash chaining; GET /audit/verify returns integrity status for a requested range. - Audit retention is ≥ 7 years; audit entries are read-only for all roles.
Blueprint Library & Versioning
"As a compliance admin, I want vetted policy blueprints I can adapt to our needs so that setup is fast and consistent with industry standards."
Description

Curated, prebuilt templates for SOC 2, HIPAA, FINRA, and GDPR covering retention, export controls, and watermarking. Templates are clonable and customizable with control mappings, jurisdiction tags, and notes. Provides semantic search, template validation, version numbers with change logs, deprecation flags, and backward-compatible updates to maintain consistency across deployments.

Acceptance Criteria
Library Coverage for Key Frameworks and Controls
Given a fresh ClipSpark Policy Blueprints installation When the Blueprint Library loads Then the library contains at least one template for each combination of framework in [SOC 2, HIPAA, FINRA, GDPR] and control in [Retention, Export Controls, Watermarking] And each template includes required fields: name, description, framework, control(s), jurisdiction tag(s), version, lastUpdatedAt, changeLog, controlMappings And each template can be opened without error and renders its fields within 2 seconds at the 95th percentile
Template Cloning and Customization Integrity
Given an existing template "HIPAA Retention (v1.0.0)" When a user clones the template Then a new template is created with a unique templateId and a provenance link to the source template And the original template remains unchanged When the user edits controlMappings, adds jurisdiction tags [US, EU], and adds a note Then the changes persist on save and are visible on reload And schema validation passes with no errors And the template diff view shows the modified fields compared to the source
Semantic Search and Faceted Filtering in Library
Given the library contains templates for SOC 2, HIPAA, FINRA, and GDPR across Retention, Export Controls, and Watermarking When the user searches for "patient data retention" Then the first page of results contains a HIPAA Retention template ranked above any non-HIPAA non-retention templates When the user applies filters framework=HIPAA and control=Retention Then only HIPAA Retention templates are shown And each result displays matched terms and jurisdiction tags And query response time is <= 300 ms at the 95th percentile for 10k templates
Template Validation Rules and Error Reporting
Given a user attempts to save a template missing jurisdiction tags or controlMappings When the save action is triggered Then the save is blocked and error messages identify the exact missing fields And error codes are returned: JURISDICTION_REQUIRED, CONTROL_MAPPINGS_REQUIRED When a user attempts to save a template with a duplicate tuple of (name, framework, control, jurisdiction, version) Then the save is blocked with error code TEMPLATE_VERSION_CONFLICT When all required fields are present and unique Then the template saves successfully and returns HTTP 201 with the templateId
Versioning, Change Logs, and Deprecation Flags
Given an existing template at v1.0.0 When a metadata-only change (e.g., note added, description edit) is saved Then the version increments to v1.0.1 and the changeLog records author, timestamp, and summary When an additive non-breaking change (e.g., additional controlMapping) is saved Then the version increments to v1.1.0 and the changeLog records the added mapping When a breaking change (e.g., removal of a controlMapping) is saved Then the version increments to v2.0.0 and the changeLog marks the change as breaking When a version is marked deprecated with a suggestedReplacement Then the deprecated version remains viewable but is hidden from new-deployment pickers by default and shows a deprecation badge
Backward-Compatible Update Propagation to Deployments
Given a deployment referencing template "GDPR Export Controls (v1.1.0)" When a patch release v1.1.1 is published (non-breaking) Then the deployment auto-updates to v1.1.1 within 5 minutes and records an audit event with oldVersion, newVersion, and changeLog summary When a minor release v1.2.0 is published (additive, non-breaking) Then the deployment prompts for update with a one-click apply and no required manual changes When a major release v2.0.0 is published (breaking) Then the deployment remains pinned to its current version until a manual migration is confirmed And users see a notification with an impact summary and migration checklist
Pre-rollout Simulation Engine
"As a program owner, I want to simulate a policy before enabling it so that I can understand and mitigate disruptions."
Description

Dry-run simulator that evaluates a selected blueprint against existing assets, users, and settings to forecast impact prior to rollout. Generates itemized reports of affected videos, pending expirations, blocked exports, watermark coverage, and policy conflicts with risk scoring and operational impact estimates. Supports scenario comparisons, scheduled simulations, and downloadable results.

Acceptance Criteria
Org-Level GDPR Blueprint Dry-Run Impact Report
Given I am a Policy Admin at the org scope And a GDPR Retention blueprint v1.4 is selected And no changes are applied (dry-run mode) When I run a simulation for the entire org Then the simulator completes without modifying any asset, user, or setting And the itemized report lists every affected video with video_id, title, team_path, project_path, owner_user_id, policy_rule_id, action_type, reason, simulated_effective_date And the report includes sections for pending_expirations, blocked_exports, watermark_coverage, and policy_conflicts And each report includes section totals and a global risk_score (0–100) plus operational_impact_estimate (impacted_user_count, estimated_editor_hours_saved) And all section totals equal the sum of itemized rows
Side-by-Side Scenario Comparison (HIPAA vs SOC 2)
Given two saved simulations with identical scope and snapshot_timestamp but different blueprints (HIPAA v2.0 and SOC 2 v1.3) When I open the Compare view Then the UI displays side-by-side totals and deltas for affected_videos, pending_expirations, blocked_exports, watermark_gaps, conflicts, risk_score, and operational_hours And I can label and persist the comparison as "HIPAA_vs_SOC2_2025-09-13" And differences at the item level can be exported as a delta CSV listing only items whose outcomes differ
Scheduled Weekly Simulation at Team Scope
Given I schedule a weekly simulation for Team "Research" every Monday at 02:00 in timezone America/New_York using the FINRA Export Controls blueprint When the scheduled time occurs Then the simulation runs even if no user is logged in And a new result is stored with scheduled_run_id, start_time, end_time, status=completed, and metrics And the last 12 results are retained and older ones are auto-archived per retention setting And failures are retried once within 30 minutes with status updated accordingly
Downloadable Results with Schema Validation
Given a completed simulation result When I download results as CSV, JSON, and Summary PDF Then the CSV and JSON conform to the published schema v1.0 with required fields [simulation_id, scope_type, scope_id, blueprint_id, blueprint_version, video_id, action_type, reason, risk_score, simulated_effective_date] And row counts in CSV/JSON equal the UI totals per section And the PDF includes summary metrics, top 10 risk drivers, and a timestamped signature block with simulation_id and hash
Permissions and Audit for Dry-Run
Given my role is Viewer at org scope When I attempt to run or schedule a simulation Then access is denied with HTTP 403 and a descriptive message Given my role is Policy Admin at project scope "Onboarding" When I run a simulation at project scope Then the action succeeds and an audit log entry is created with actor_id, scope, blueprint_id, blueprint_version, read_only=true, started_at, finished_at, result_checksum
Performance and Scalability Thresholds
Given an organization with 100,000 videos, 10,000 users, and 500 projects When I run an org-scope simulation with the GDPR blueprint Then the simulation completes within 15 minutes P95 and 30 minutes P99 And peak memory usage does not exceed 6 GB on a standard large worker And the results view paginates with page load under 2 seconds P95 for 10,000-row pages
Parity with Enforcement Engine on Fixture Set
Given a fixture dataset and recorded outputs from the production policy enforcement engine for the same snapshot in time When I run the simulator using identical blueprint versions and options Then predicted outcomes match enforcement engine outcomes with 6>= 99.5% item-level agreement and 100% agreement on high-risk actions (block_export, forced_watermark) And any mismatches are listed in a reconciliation report with item identifiers and rule_id
Guided Gap Remediation
"As a team lead, I want guided steps to resolve compliance issues so that my projects meet policy without manual guesswork."
Description

Actionable recommendations to resolve compliance gaps identified by simulation or monitoring, such as missing watermarks, misaligned retention periods, or overly broad export permissions. Offers one-click safe auto-fixes, batched bulk updates, targeted notifications to owners, and verification checks that confirm remediation success, with progress tracking across scopes.

Acceptance Criteria
One-Click Auto-Fix: Missing Watermarks (Team Scope)
Given a Compliance Admin selects a Team scope with videos flagged "Missing watermark" by simulation or monitoring When the admin confirms the Auto-fix action after reviewing the preview Then the system applies the active watermark template from the Policy Blueprint to all flagged videos within the selected scope And no videos outside the selected scope are modified (0 out-of-scope changes) And a remediation job is created with a unique ID and progress visible in the dashboard And the job processes at least 500 videos within 5 minutes And the result summary shows counts for succeeded, skipped (with reason), and failed (with error code) And each remediated video is rechecked and marked Resolved only if the watermark is detected
Batched Retention Alignment Across Projects
Given there are one or more Projects with retention period mismatches against the selected Policy Blueprint When a user selects those Projects and triggers Batch Update to align retention Then each impacted Project retention policy is updated to the blueprint’s value without altering unrelated policies And effective retention on all affected videos reflects the new value within 10 minutes And videos on legal hold or with explicit overrides are skipped and reported with reason "Override" And an audit log is recorded per project with before/after values, actor, timestamp, and scope And a CSV report of changes is available for download from the job detail
Targeted Notifications for Owner-Actioned Export Narrowing
Given remediation requires owner approval to narrow export permissions on identified folders or projects When the remediation plan is initiated Then only owners of affected resources receive a notification containing a scoped list of items and one-click Approve/Narrow links And notifications are delivered via the owner’s preferred channel (email or Slack) within 5 minutes And each owner receives at most one digest per hour per remediation job And delivery status (sent, bounced, read) is tracked and visible in the job detail And no notifications are sent to users without ownership or delegated responsibility
Post-Remediation Verification and Success Checks
Given a remediation job completes processing When automatic verification runs Then 100% of assets marked "succeeded" pass the specific compliance checks that motivated the fix (watermark present, retention value equals blueprint, export scope is not broader than policy) And any asset failing verification is reclassified from "succeeded" to "failed" with an error code and remediation suggestion And a verification report (CSV and JSON) is generated containing asset IDs, check results, timestamps, and verifier version And the job’s final status is "Verified Pass" only if verification success rate equals 100%; otherwise "Verified Fail" with details
Impact Simulation Approval Gate Before Remediation
Given a user initiates Auto-fix or Batch Update from a simulation When the preview is generated Then the preview displays predicted counts by gap type (to be fixed, skipped, at-risk), list of affected scopes, and out-of-scope change risk equals 0 And the Confirm button remains disabled until the user acknowledges the summary and selects "Apply to [Scope]" And if predicted failures > 0 or out-of-scope risk > 0, the system requires the user to adjust scope or automatically excludes those items and regenerates the preview And the job cannot start without explicit confirmation recorded in the audit log
Cross-Scope Remediation Progress Tracking Dashboard
Given a Compliance Admin opens the Remediation Progress dashboard When they filter by Organization, Team, Project, gap type, and time range Then the dashboard displays counts of gaps by status (Open, In Progress, Resolved, Failed), jobs queued/running/completed, and percent complete per job with ETA And data freshness is less than or equal to 60 seconds and indicated by a "Last updated" timestamp And exporting the current view to CSV completes within 30 seconds and includes applied filters And clicking any count drills down to a list of assets or jobs matching that metric
Audit Evidence Export
"As a compliance officer, I want comprehensive audit evidence exports so that I can satisfy auditors quickly and reduce audit risk."
Description

On-demand and scheduled export of audit evidence including current and historical policy definitions, blueprint versions, control mappings, scope assignments, enforcement logs, approvals, exceptions, and simulation reports. Supports PDF, CSV, and JSON with digital signatures, timestamps, user IDs, and secure delivery to auditor inboxes or storage destinations.

Acceptance Criteria
On-Demand Export with Scoped Filters
Given an authorized compliance admin selects a time range, scopes (org/team/project), and artifact types on the Audit Evidence Export screen When they click Export Now Then a new export job with a unique ID is created and visible in the Export Jobs list with status Processing And upon completion the job status changes to Completed and the download link is available to the requester And the exported package contains only the selected scopes and artifacts within the selected time range And each exported file embeds the generation timestamp (UTC, ISO 8601) and the initiator user ID in metadata or header rows/fields
Scheduled Exports and Time Zone Compliance
Given an authorized compliance admin creates a schedule specifying frequency (daily/weekly/monthly), execution time, time zone, and delivery destinations (emails and/or storage) When the scheduled time occurs Then the export runs in the specified time zone window and produces an export job with a unique ID And recipients/destinations receive the export without manual intervention And pausing, resuming, or deleting the schedule updates the next-run time accordingly and prevents unintended runs And failures trigger a notification to the schedule owner and are visible with error details on the Export Jobs list
Evidence Completeness Across Artifacts and History
Given a full-coverage export is requested for a defined time range and scope When the export completes Then the output includes current and historical policy definitions, blueprint versions, control mappings, scope assignments, enforcement logs, approvals, exceptions, and simulation reports And historical items reflect the versions effective during the selected time range And counts of items per artifact type match system-of-record queries for the same filters And missing or empty sections are explicitly represented as empty datasets with headers/schemas intact
Multi-Format Output Validation (PDF, CSV, JSON)
Given the requester selects one or more output formats (PDF, CSV, JSON) When the export completes Then a separate deliverable is produced for each selected format And CSV files are UTF-8 encoded with a single header row, comma-delimited, RFC 4180 compliant, and include stable column order matching the documented schema And JSON files conform to the documented JSON schema for each artifact, with valid types and required fields present And PDF includes labeled sections for each artifact with readable tables and section bookmarks for navigation And sample records for each artifact match across formats by primary identifier and field values
Digital Signatures, Timestamps, and User Attribution
Given any generated export file (PDF, CSV, or JSON) When the file is verified against ClipSpark’s published public certificate Then the digital signature verification succeeds and indicates the file is unmodified since signing And every file carries an embedded generation timestamp in ISO 8601 UTC and the initiator user ID And the signature covers the entire file content to provide tamper evidence; any modification causes signature verification to fail
Secure Delivery to Auditor Inboxes and Storage Destinations
Given delivery settings specify auditor email recipients and/or a storage destination (e.g., S3, GCS, Azure Blob) with valid credentials When an export job completes Then email recipients receive a secure, time-limited download link over TLS; the link expires after the configured validity window and requires recipient verification And storage destinations receive the files via secure upload with encryption at rest enabled (provider-native) and integrity checks (e.g., ETag/MD5) recorded And delivery failures (bounce, permission denied, network error) are retried per backoff policy and surfaced in job details with final status Failed if not recoverable
Authorization, Audit Trail, and Job Observability
Given role-based access control is enforced for exports When a non-privileged user attempts to create or view an export Then access is denied with an explanatory message and no job is created And when an authorized user runs an export, an immutable audit log entry records job ID, requester user ID, timestamp, scope, filters, selected artifacts, formats, destinations, and outcome And the Export Jobs list and detail view display real-time status (Queued/Processing/Completed/Failed), start/end times, file sizes, and delivery results And export cancellation by an authorized user transitions the job to Canceled and prevents partial deliverables

SCIM SmartMap

Map identity attributes and groups to roles with a visual rule builder (e.g., if Department=Sales then Export=Denied). Preview deltas before syncing, run dry-runs, and auto-rollback on errors—preventing over-permissioning and making onboarding/offboarding effortless.

Requirements

Visual Rule Builder for Attribute & Group Mapping
"As an IT admin, I want to visually map identity attributes and groups to ClipSpark roles so that I can enforce least-privilege access without writing code."
Description

A drag-and-drop rule composer to map SCIM attributes (e.g., department, title, employmentStatus) and IdP groups to ClipSpark roles and permission scopes. Supports simple conditions, compound logic (AND/OR), nested groups, and value transforms (lowercase, trim, regex match). Provides reusable rule templates and inline schema discovery from connected IdPs. Ensures live validation, sample data preview, and instant conflict warnings. Persists versions for change tracking and rollback. Integrates with ClipSpark RBAC and sensitive privileges such as Export, Caption Edit, and Highlight Publish to enforce least privilege.

Acceptance Criteria
Drag-and-Drop Mapping to Roles & Permission Scopes
Given a connected IdP exposing attributes department, title, employmentStatus and groups Sales, Marketing When the admin drags an attribute condition "department equals Sales" into the canvas and maps it to role "Viewer" with permission override "Export:Denied" Then the rule is syntactically valid and Save is enabled And When saved, the rule is persisted and retrievable; reloading the builder shows the rule identically And When evaluating a sample user with department=Sales Then the preview shows role Viewer applied and Export permission set to Denied And When evaluating a sample user not matching any rule Then no role or permission changes are previewed
Compound Logic and Value Transforms Support
Given conditions A: title equals "Engineer", B: group equals "QA", C: employmentStatus equals "Active" When the admin nests those as (A AND (B OR C)) with at least 3 levels of grouping Then preview evaluation aligns with the logical truth table for at least 8 combinations of A/B/C And Grouping/precedence is visually indicated and persists after save/reload And Given transforms trim and lowercase are applied to attribute "Title" with input " Senior Engineer " When comparing against "senior engineer" Then the condition evaluates true and the transform order is preserved in saved rule metadata And Given a regex match ^Eng.*$ applied to title Then users with titles "Engineer" and "Engineering Manager" match; "Product Manager" does not
Inline Schema Discovery & Live Validation
Given an IdP connection with schema attributes fetched successfully When the admin opens the attribute picker Then the list displays attribute names and types from the IdP, including custom attributes; unknown entries are flagged And Validation runs on each edit, highlighting undefined attributes, invalid operators, and malformed regex with messages adjacent to the offending field And Save is disabled while any error is present and enabled once all errors are resolved And If schema fetch fails, a retry control appears and manual entry remains possible with a warning; no crash occurs
Sample Data Preview & Conflict Warnings
Given at least 10 sample principals are loaded from the IdP or CSV upload When the admin clicks Preview Then each row shows matched rule IDs, before/after roles, and before/after permission scopes And The preview executes for 100 rows in under 2 seconds on a typical org dataset And When two rules assign contradictory outcomes to the same permission (e.g., Export Allowed vs Denied) for the same principal Then a conflict banner lists the rule IDs, highlights impacted principals, and blocks Save/Publish until resolved by reorder, edit, or explicit override selection
Reusable Rule Templates
Given an admin creates a rule and saves it as a template named "Sales Read-Only" with a description and tags When another admin applies that template Then the builder inserts the template as a new rule and prompts for variable placeholders (e.g., Department) before enabling Save And Template usage records the template version; applying an outdated version prompts to upgrade or keep as-is And Templates can be searched, shared within the org, and soft-deleted; soft-deleted templates are hidden from new use but remain in history
Versioning & Rollback
Given any change is saved Then a new configuration version is created capturing author, timestamp, change summary, and diff of rules And When viewing history, the user can compare any two versions and see added/removed/modified conditions And When performing a rollback to version N, the current rules are replaced by version N, a new version is created noting the rollback, and the audit log records who performed it and when And Rollback occurs without downtime; preview immediately reflects the rolled-back configuration
RBAC Enforcement for Sensitive Privileges
Given mapping rules assign role "Editor" but explicitly set "Caption Edit:Denied" and "Export:Denied" When a mapped principal signs into ClipSpark Then the effective RBAC grants allow general edit functions but block Caption Edit and Export actions at the UI and API layers with 403 responses And When the rule is removed and access re-evaluated, those actions become available according to the baseline role And Enforcement is verified across Export from player, caption editing UI, and highlight publish action
Rule Priority & Conflict Resolution Engine
"As a security architect, I want clear rule precedence and explainability so that conflicting mappings do not grant unintended permissions."
Description

A deterministic evaluation engine that orders rules by priority, supports explicit tie-breakers, and resolves conflicts between attribute- and group-based assignments. Includes allow/deny semantics, default fallbacks, and per-permission overrides so that sensitive actions (e.g., Export=Denied) take precedence. Exposes a simulation mode that shows which rule fired and why, with explainability trails. Provides safeguards against over-permissioning via deny-first evaluation for high-risk privileges and guardrails against blanket grants.

Acceptance Criteria
Deterministic Priority Ordering and Tie-Breakers
Given a rule set with A(priority=50,tiebreak=10), B(priority=50,tiebreak=5), C(priority=40) and a subject S that matches A and B When the engine evaluates S across 10 repeated runs and on 3 distinct nodes Then the winning rule is A in every run and the evaluation order is [A,B,C] And the final permission set is identical across all runs and nodes And the evaluation trace contains the ordered rules, the tie-breaker key used (tiebreak), and the losing rule IDs
Attribute vs Group Conflict Resolution
Given an attribute-based rule RA (Department=Sales) that allows Edit and Export at priority=40 and a group-based rule RG (Group=Contractors) that denies Export at priority=45 and a subject S in Sales and Contractors When the engine evaluates S Then Export is Denied and Edit is Allowed And the trace cites RG as the winning rule for Export with reason "higher priority deny over allow" And given a second case where RA and RG both have priority=40 When the engine evaluates S Then Export is Denied due to deny precedence for high-risk permissions at equal priority
Deny-First Evaluation for High-Risk Privileges
Given a configured high-risk set {Export, DeleteProject, ManageSSO} and a subject S matched by an allow-Export rule at priority=80 and a deny-Export rule at priority=60 When the engine evaluates S Then Export is Denied and the trace marks highRiskDenyPrecedence=true And given multiple matching rules where at least one denies DeleteProject at any priority When the engine evaluates S Then DeleteProject is Denied regardless of any allows And the trace shows the denying rule IDs and the precedence rationale
Default Fallback on No Matching Rules
Given a subject S that matches no rules When the engine evaluates S Then S is assigned the baseline role Viewer and permissions: View=true, Edit=false, Export=false, ManageSSO=false And the trace records reason="fallback" with no winning rule ID And repeated evaluations of S return the same baseline result
Guardrails Against Blanket Grants
Given a proposed rule R that grants AllPrivileges or any high-risk allow to a wildcard or broad group and affects ≥ BlanketGrantThreshold (>=100 users or >=25% of active accounts, whichever is lower) When attempting to save or apply R (preview or sync) Then the operation is blocked with error code BLANKET_GRANT_GUARDRAIL and no changes are applied And if an authorized SecurityAdmin provides breakGlass=true and a justification of at least 20 characters Then the operation may proceed and the trace logs the approver, timestamp, and justification
Simulation Mode Explainability Output
Given a subject S and a rule set of up to 100 rules When simulation mode is run for S Then the response includes: evaluationId (UUID), subjectSnapshot (hash), orderedEvaluations (ruleId, matched, priority, tiebreak, specificity), winningRule per permission, tieBreakReason, and highRiskDeny flags And the response returns within 2 seconds And the simulation clearly surfaces which rule fired for each permission and why
Per-Permission Override Precedence
Given a role grant rule assigns Editor (includes Export=Allow) at priority=70 and a per-permission override rule denies Export for Department=Sales at priority=30 and subject S has Department=Sales When the engine evaluates S Then Export is Denied while other Editor permissions remain Allowed And the trace shows the override rule as winner for Export only with reason="per-permission override precedence"
Delta Preview & Dry-Run Simulator
"As an IT operator, I want to preview the changes a sync would make so that I can catch mistakes before impacting users."
Description

A non-destructive preview of provision/deprovision deltas prior to syncing, including adds, updates, removals, and permission changes per user. Supports sampling and full-tenant previews, with filters by department, group, or role. Displays impact metrics and exportable CSV/JSON reports. Allows dry-run execution with side effects suppressed and detailed results, errors, and rule-fire explanations logged for review. Integrates with the rule engine and RBAC to present accurate outcomes before applying changes.

Acceptance Criteria
Full-Tenant Delta Preview with Metrics
Given a tenant with up to 50,000 identities and an active rule set When a Full Preview is initiated Then per-identity deltas include add, update, remove, and permission_change classifications And no write operations are issued to external targets (0 POST/PATCH/DELETE events) And the preview completes within 120 seconds for ≤50k identities And metrics display total_processed, adds, updates, removals, permission_changes, affected_roles, affected_groups, error_count And results are deterministic for identical input snapshot and rule set
Filtered Preview by Department, Group, and Role
Given filters Department='Sales', Group='Podcast Hosts', and Role='Editor' When a Filtered Preview is run Then only identities satisfying all provided filters are included (logical AND) And displayed counts equal the number of identities matching the same filters in the identity store (±0) And clearing any filter updates the result set and counts accordingly within 2 seconds And the metrics and export respect the active filters
Sampling Mode Preview
Given a population of N identities and Sampling mode enabled with percentage=5% and seed='abc123' When a Sampling Preview is run Then the sample size equals ceil(0.05 × N) And the sample selection is uniformly random and reproducible for the same seed And changing the seed produces a different sample And the UI labels the run as 'Sampling' and the export contains only sampled identities
Dry-Run Execution with Side Effects Suppressed
Given Dry-Run mode is enabled When the simulation is executed Then no side effects occur on downstream systems (verified by zero state changes and zero write API calls) And each identity record includes action, before_state, after_state, rules_fired[], and simulated_requests[] in the results And the run emits a unique run_id, correlation_id, start/end timestamps, and error_list And results remain accessible for review for at least 24 hours
Exportable Reports (CSV and JSON)
Given preview or dry-run results are available with M records When the user exports CSV Then a file with exactly M data rows (excluding header) is generated within 30 seconds for up to 50k records And columns include run_id, user_id, action, from_roles, to_roles, from_groups, to_groups, rules_fired, error_code, error_message, timestamp When the user exports JSON Then the schema contains the same fields with identical counts And exported files are named {feature}-run_{run_id}-{timestamp}.{ext} and a checksum is provided
RBAC Enforcement and Audit Logging
Given RBAC permission 'SCIM:Preview' is required When a user without this permission attempts to run a preview or dry-run Then the request is denied with HTTP 403 and no result metadata is leaked When a permitted user runs a preview or dry-run Then an audit record is written containing actor_id, run_id, run_type, filters, sample_params, rule_set_version, metrics, and start/end timestamps And audit records are retained for at least 90 days and can be queried by run_id
Rule-Fire Explanations and Rollback Simulation
Given a rule set with named rules and a rollback threshold of 1% When a preview or dry-run is executed Then each resulting delta lists rules_fired with rule_name, condition_summary, matched_attributes, and priority And any item with a conflict or validation failure is marked with error_code and explanation And if error_rate ≥ 1% of processed items then the run outcome is 'would_rollback', commit actions are disabled, and a rollback summary is included in the results
Transactional Sync with Auto-Rollback & Retry
"As a platform engineer, I want syncs to be transactional with automatic rollback so that failures don’t leave users in an inconsistent state."
Description

Execution of provisioning in atomic batches with idempotent operations; on error, automatically roll back to the last consistent state and surface diagnostics. Supports exponential backoff retries, partial failure isolation, and a circuit breaker to prevent cascading issues. Maintains a durable sync checkpoint and ensures eventual consistency across the IdP and ClipSpark RBAC. Includes configurable batch sizes, concurrency, and rate limits per provider to respect IdP quotas.

Acceptance Criteria
Atomic Batch Provisioning with Full Rollback on Error
Given a batch of provisioning operations against ClipSpark RBAC and a captured pre-batch snapshot When any operation in the batch fails with a retriable or non-retriable error Then all mutations from that batch are reverted and the post-rollback RBAC state equals the pre-batch snapshot And no new users, role assignments, or group links from the failed batch persist in ClipSpark And an audit record exists with fields {batchId, failedOperationId, errorCode, errorType, rollbackStatus=success, durationMs}
Idempotent Operations Ensure No Duplicates on Retry
Given a batch with idempotencyKey K applied successfully When the same batch (same K, same operations) is retried due to timeout or unknown completion Then no additional side effects occur and the resulting RBAC state is unchanged And the API response indicates idempotentReplay=true and deduped=true And the audit log contains a single committed entry per logical operation (no duplicates)
Exponential Backoff With Bounded Retries Per Provider
Given provider P has retryPolicy {base=500ms, factor=2, jitter=±20%, maxDelay=30s, maxAttempts=5} and rateLimit=10 QPS When transient errors (HTTP 429/502/503 or network timeout) occur Then retries are scheduled with delays within jitter bounds and never exceed maxDelay nor maxAttempts And the observed request rate to P never exceeds 10 QPS across concurrent workers And failures after maxAttempts are surfaced with retryExhausted=true and lastErrorCode present
Circuit Breaker Prevents Cascading Failures
Given error rate over a 60s window exceeds 50% or 5 consecutive failures occur for provider P When the threshold is reached Then the circuit state transitions to open for the configured cooldownDuration And new requests to P during open state fail fast with status=circuit_open and are not sent upstream And after cooldown, a single half-open probe is sent; on success the circuit closes, on failure it reopens And breaker state transitions and reasons are exported via metrics and logs with fields {provider, fromState, toState, reason, timestamp}
Partial Failure Isolation Across Batches and Providers
Given concurrent syncs for providers A and B or organizational partitions When a batch for provider A fails and rolls back Then batches for provider B continue and can complete successfully without being cancelled And the global sync job reports status A=failed, B=succeeded with separate batchIds and metrics And no rollback is triggered for batches unrelated to A
Durable Checkpointing and Resume from Last Consistent State
Given a long-running sync with committed batch N and in-flight batch N+1 When the process crashes or is terminated Then on restart the orchestrator resumes from the checkpoint for committed batch N and does not reapply batches <= N And batch N+1 is either retried idempotently or rolled back before reattempt, producing a single committed result And the target RBAC state converges to the IdP snapshot at the resumed high-water mark within the configured SLA window
Provider Limits: Configurable Batch Size, Concurrency, and Rate Compliance
Given provider P configured with {batchSize=200, maxConcurrency=4, rateLimit=8 QPS} When a sync runs Then the orchestrator never sends more than 200 operations per commit unit, never exceeds 4 in-flight requests, and observed QPS to P stays ≤ 8 averaged over 1s windows And dynamic changes to these settings take effect within the next scheduling interval without process restart And 429 responses, if received, trigger backoff and schedule adjustments that restore compliance within 2 scheduling intervals
SCIM Connector Integrations (Okta, Azure AD, OneLogin)
"As an enterprise admin, I want out-of-the-box connectors to my IdP so that I can deploy SCIM SmartMap without custom development."
Description

Standards-compliant SCIM 2.0 connectors for leading IdPs with OAuth 2.0/OIDC authentication, schema discovery, incremental sync, and push-based webhooks where available. Provides connector health checks, connectivity tests, and per-connector mapping profiles. Supports custom attribute mapping, pagination, throttling, and change notifications. Secures secrets via KMS and supports cloud-agnostic deployment to fit ClipSpark’s enterprise environments.

Acceptance Criteria
OAuth/OIDC Authentication and Secret Management for IdP Connectors
Given valid OAuth 2.0/OIDC credentials for Okta, Azure AD, and OneLogin When an admin configures a connector and initiates authorization Then the appropriate OAuth flow (Auth Code + PKCE or Client Credentials) completes successfully for the selected IdP And access/refresh tokens are stored encrypted using the configured KMS provider And secrets are never rendered in plaintext in UI, logs, or APIs (redacted by default) And token refresh occurs automatically with at least a 5-minute buffer before expiry And a connectivity test using the stored credentials returns success with HTTP 200 within 3 seconds And failed authorization displays a provider-specific, actionable error message and does not persist any secrets
SCIM 2.0 Users/Groups Compliance
Given a configured connector When SCIM requests are made to /Users and /Groups endpoints Then Create, Read, Update (PUT/PATCH), and Delete operations conform to RFC 7643/7644 And required attributes (id, schemas, userName for Users; displayName for Groups) are validated and errors returned with SCIM-compliant responses And ETags are returned and If-Match is enforced for update concurrency control And filtering with eq on userName and externalId is supported And pagination via startIndex and count is supported and totalResults is accurate And responses use correct HTTP status codes (200/201/204/400/404/409/412/429) and error payloads with scimType when applicable
Incremental Sync, Pagination, and Throttling Controls
Given a prior successful sync with stored cursor (timestamp, ETag, or provider delta token) When an incremental sync is initiated Then only records changed since the cursor are fetched and processed And pagination retrieves all pages until totalResults are exhausted without duplication or loss And sync throughput handles at least 100k users and 10k groups per run And 429/5xx responses trigger exponential backoff with jitter and respect Retry-After And the sync resumes from the last successful page on retry without reapplying completed changes (idempotent) And end-to-end incremental sync completes within the configured window (default ≤15 minutes for 100k users) and persists a new cursor
Push-Based Change Notifications and Idempotent Processing
Given a connector for an IdP that supports push notifications (e.g., Okta Event Hooks, Azure AD Change Notifications, OneLogin Events) When a subscription is created Then endpoint verification/handshake succeeds per provider protocol and secrets/signing keys are stored via KMS And incoming notifications are signature/validation-token verified and unauthorized requests are rejected with 401/403 And each event has an idempotency key; duplicates are ignored while guaranteeing exactly-once application And acknowledged webhooks return 2xx within 2 seconds and enqueue processing asynchronously And failures retry with exponential backoff up to a configured limit and are dead-lettered with alerting
SmartMap Role Mapping with Profiles, Preview, Dry-Run, and Auto-Rollback
Given per-connector mapping profiles are enabled When an admin defines rules (e.g., if Department = "Sales" then Export = Denied; map Groups to Roles) Then rule evaluation is deterministic (explicit priority; Deny overrides Grant) and produces a single resolved role set per user And a Preview shows before/after assignments and attribute changes for a selected cohort without side effects And a Dry-Run executes the full sync pipeline against the upcoming delta and produces a downloadable report And if projected changes exceed guardrails (e.g., >1% role escalations or any Admin grant outside allowlist), execution is blocked And on runtime errors affecting ≥1% of operations or any critical failure, the system auto-rolls back to the pre-sync state and marks the run as failed And mapping profiles are versioned, can be exported/imported, and switching the active profile is atomic
Per-Connector Health Checks and Connectivity Tests
Given a configured connector When "Test Connection" is executed Then the system validates credentials, required API scopes, and endpoint reachability and returns a result within 3 seconds And the connector exposes health status as Connected/Degraded/Disconnected based on last successful sync time and recent error rate thresholds And a degraded or disconnected state generates an audit entry and emits an alert event And health details include last sync timestamp, last error (if any), and next scheduled sync time
Cloud-Agnostic Deployment and KMS Abstraction
Given deployments on AWS, Azure, and GCP When the connector service is provisioned with cloud-specific configuration Then KMS operations use the selected provider (AWS KMS, Azure Key Vault, GCP Cloud KMS) via a common interface And all secrets encryption/decryption operations succeed with p95 latency ≤300 ms per call in each cloud And no provider-specific SDKs leak into business logic (build once, run anywhere container) And integration tests for each cloud pass for auth, secret storage, webhook handling, SCIM CRUD, and sync flows without code changes
Audit Logging & Alerting for Provisioning Events
"As a compliance officer, I want comprehensive audit logs and alerts so that I can demonstrate control over access changes and react to anomalies."
Description

A tamper-evident, searchable audit trail capturing rule changes, sync executions, dry-runs, deltas, and permission grants/denials by user. Provides retention policies, export to SIEM platforms (e.g., Splunk, Datadog), and real-time alerts for high-risk changes such as mass export enablement. Includes who/when/what with before/after snapshots and correlation IDs across systems to support compliance reporting and incident response.

Acceptance Criteria
Comprehensive Event Capture with Before/After Snapshots
Given SCIM SmartMap is enabled and a user performs any of: rule change, sync execution (live), dry-run, delta preview, or permission grant/denial When the action completes (success or failure) Then an audit record is written that includes: event type, actor (user/service), UTC timestamp in ISO 8601 with milliseconds, target entity identifier, before/after snapshots (JSON), outcome status, correlation ID, request ID, originating IP, and client app/version And the audit record is available for search within 30 seconds of the event time And the record is retrievable and filterable by actor, event type, target, correlation ID, and time range And search query latency is ≤ 2 seconds p95 for queries over ≤ 30 days returning ≤ 1,000 records And access controls prevent users without Audit Viewer role from viewing records; redacted fields are masked per data policy
Tamper-Evident Audit Log Integrity
Given audit logs are written to an append-only store with a cryptographic hash chain When a new audit record is appended Then the chain hash and record-level signature are computed and stored And a public Verify Integrity API/UI validates the chain over a selected time range and returns 'valid' for unaltered sequences And any detected alteration or deletion outside retention policy triggers an Integrity Alert within 60 seconds and records the verification failure with details And Verify Integrity completes within 2 minutes p95 for 1,000,000 records
Real-Time High-Risk Change Alerts
Given alerting is configured with channels (email, Slack, webhook) and thresholds for high-risk events (e.g., enabling export for a group with >100 members, mass export enablement, admin role assignment) When a high-risk event occurs Then an alert is delivered to all configured channels within 60 seconds p95 including actor, timestamp, event type, impacted entities/count, before/after summary, and correlation ID And duplicate alerts for the same correlation ID within 10 minutes are deduplicated with a reference count And delivery failures are retried with exponential backoff (3 attempts) and failures after retries are logged and visible in alert health And alerts can be acknowledged to suppress repeats for 60 minutes per correlation ID
SIEM Export to Splunk and Datadog
Given SIEM export is configured with valid credentials and field mappings When new audit records are created Then records are streamed to Splunk HEC and Datadog Logs using JSON schema v1 within 120 seconds p95 of creation And operators can filter included event types and redact fields before export And if the SIEM endpoint is unavailable, events are durably buffered for at least 72 hours and delivered without duplication upon recovery And export health shows last successful push time, backlog size, and error rate over the past 1 hour
Configurable Retention and Legal Hold
Given a retention policy between 30 and 365 days is configured with optional legal hold by case ID When an audit record reaches its retention expiry and is not under legal hold Then it is purged within 24 hours and the purge action is itself logged with actor=system and correlation to the original record And records under legal hold are excluded from purge until the hold is released; upon release they follow the active retention policy And an administrator can export all records matching a query before purge and exports up to 1,000,000 records complete within 15 minutes p95 And integrity proofs remain verifiable for retained segments after purges
Searchability and Cross-System Correlation
Given a user with Audit Viewer role opens the audit search UI or API When they query by actor, event type, date range, target entity, or correlation ID Then results return within 2 seconds p95 for up to 1,000 records and support pagination, sorting, and time zone display in UTC And selecting a record reveals before/after snapshots side-by-side and a copyable correlation ID And using the correlation ID, related records across rule changes, sync executions, and permission events are linked and retrievable via a Related Events view/API And exporting current search results to CSV and JSON produces files within 60 seconds for up to 10,000 records

GeoFence Exports

Enforce country, region, and IP-based controls on downloads and shares. Block or allow by domain, flag ITAR/EAR content, and honor data residency—stopping non-compliant exports at the source while giving admins clear, actionable controls.

Requirements

Granular Geo-IP Enforcement Engine
"As a compliance administrator, I want to automatically block exports by country, region, or IP so that non-compliant downloads and shares are prevented at the source without manual intervention."
Description

Implements real-time country, region, and IP-based access control for all export surfaces (downloads, share links, API exports) within ClipSpark. Uses reputable IP intelligence (IPv4/IPv6, proxy/VPN detection) to evaluate requests at the CDN/edge with a <50ms latency budget. Supports state/province-level rules where data is available, custom geo groups (e.g., "EU", "ANZ"), allow/deny lists, and configurable precedence across geo, IP, and domain rules. Fails closed on lookup errors/timeouts and caches decisions with short TTL to maintain performance. Applies consistently to authenticated users and anonymous link recipients, including resumable downloads and streaming previews. Provides comprehensive logging of decisions and reasons for auditability and integrates with existing permission checks and rate limiting.

Acceptance Criteria
Edge Decision Latency and Consistency Across Export Surfaces
Given geo allow/deny policies are configured and active And representative test IPs from allowed and denied locations are available When requests are made to downloads, share-link access, API exports, and streaming preview segment endpoints Then the p95 geo decision latency measured at the CDN/edge for each surface is <= 50ms And allowed requests succeed per surface’s normal response contract And denied requests return HTTP 403 with machine-readable reason GEO_DENY And for identical IP and headers, the allow/deny decision is consistent across all export surfaces within the cache TTL
IPv4/IPv6 Coverage and Anonymizer/VPN Proxy Detection
Given policies that deny anonymizer/VPN/proxy traffic are enabled And test traffic is generated from IPv4, IPv6, and known VPN/proxy egress IPs When requests are evaluated by the geo-IP engine Then IPv4 and IPv6 addresses are both classified correctly by country/region And requests from known anonymizer/VPN/proxy IPs are denied with reason ANONYMIZER_BLOCKED And requests from non-anonymizer IPs in allowed locations are allowed And toggling the anonymizer policy off results in those same anonymizer/VPN/proxy requests being allowed
State/Province-Level Rules Where Available
Given a country is allowed (e.g., US) and specific regions within it are denied (e.g., US-CA), and region data is available for the requester IP When requests originate from within the denied region Then those requests are denied with reason REGION_DENY while requests from other regions in the allowed country are allowed And when region data is unavailable for an IP, the country-level rule is applied And when only a region-level allow exists within an otherwise denied country, only IPs resolvable to that region are allowed
Custom Geo Groups and Configurable Rule Precedence (Geo vs IP vs Domain)
Given a custom geo group (e.g., EU = [DE, FR, ES]) is defined and allowed And an explicit IP deny list contains specific requester IPs And a recipient domain allow list contains example.edu And the precedence is configured as IP > Domain > Geo When a request originates from an IP on the deny list with recipient domain example.edu inside the allowed geo group Then the request is denied per precedence with reason IP_DENY When the precedence is changed to Domain > IP > Geo and the same request is retried Then the request is allowed per precedence due to domain allow, despite the IP deny And anonymous link access with no recipient domain present ignores domain rules and follows IP/Geo precedence
Fail-Closed on Provider Errors and Short-TTL Caching Behavior
Given the IP intelligence provider experiences a timeout or error during lookup When a request requires geo evaluation Then the engine fails closed and denies the request with reason FAIL_CLOSED And the denial is logged with error context and provider status Given a cache TTL in seconds is configured (short duration) When a decision is made and cached Then subsequent identical requests within TTL are served from cache And after TTL expiry, the next request is re-evaluated against current rules and fresh IP intelligence
Uniform Enforcement for Authenticated and Anonymous, Including Resumable and Streaming
Given the same geo policies apply to authenticated users and anonymous share-link recipients When an authenticated user and an anonymous recipient access the same resource from the same IP Then both receive the same allow/deny decision and reason Given a resumable download where part 1 was allowed and the policy changes to deny mid-transfer When a subsequent byte-range request is made to resume Then the resume request is denied with reason GEO_DENY and the transfer is halted Given HLS/DASH preview playback When sequential media segment requests are made from a denied location Then each segment request is denied, preventing playback
Audit Logging, Decision Explainability, and Integration with Permissions and Rate Limiting
Given an access attempt occurs on any export surface When the geo-IP engine evaluates the request Then an audit log entry is recorded including: timestamp, request ID, actor type (authenticated/anonymous), content/resource ID, surface (download/share/API/stream), source IP, resolved country/region, anonymizer flag, matched rule and rule source (Geo/IP/Domain/Group), precedence configuration snapshot, decision (ALLOW/DENY/FAIL_CLOSED), and evaluation time And logs contain no secret tokens or content payloads And if a base permission check denies access, the geo engine is not evaluated and the decision is PERMISSION_DENIED And if rate limiting blocks a request, the geo engine is not evaluated and the decision is RATE_LIMITED And when base permission checks pass and rate limits are not exceeded, geo evaluation occurs and the combined result is enforced
Domain Allow/Deny Controls for Share Targets
"As an organization admin, I want to restrict exports to a vetted set of partner domains so that content is only accessible to approved organizations."
Description

Adds policy-based restrictions that limit exports to approved recipient domains and block disallowed domains for both invite-based sharing and link-based downloads. Validates recipient domains via SSO claims, email verification, or federated identity where applicable. Supports wildcards (e.g., *.partner.com), mixed-mode policies (allowlist with explicit deny entries), and alignment with geo/IP rules using a deterministic precedence order. Includes controls for handling consumer email providers, optional referrer checks for embedded players, and exception windows with auto-expiry. Exposes an admin UI and API for policy management, with versioned changes and audit history.

Acceptance Criteria
Invite-Based Sharing: Allowlist with Explicit Deny Precedence
Given a domain policy with allowlist [partner.com, *.subsidiary.com] and denylist [bad.partner.com] And a user attempts to share via invite When the recipient email domain is bad.partner.com Then the invite is blocked with HTTP 403 and error code DOMAIN_DENY And the UI shows an actionable message including the blocked domain and policy version ID And an audit event is recorded with actor, recipient email, matched rule, and policy version Given the same policy When the recipient email domain is eng.subsidiary.com Then the invite is permitted and sent successfully And an audit event is recorded with actor, recipient email, matched rule, and policy version Given the same policy When the recipient email domain is external.com (not on allowlist) Then the invite is blocked with HTTP 403 and error code DOMAIN_NOT_ALLOWED And an audit event is recorded with actor, recipient email, matched rule, and policy version
Link-Based Download: Authenticated Requester Domain and Consumer Provider Handling
Given a link-based download that requires authentication and a policy with allowlist [*.customer.com] and consumer provider blocking enabled [gmail.com, yahoo.com, outlook.com] When an authenticated requester has an SSO-verified email domain of video.customer.com Then the download is allowed and completes with HTTP 200 And an audit event records requester identity, matched rule, and policy version Given the same policy When an authenticated requester has an email domain of gmail.com Then the download is blocked with HTTP 403 and error code CONSUMER_DOMAIN_BLOCKED And an audit event is recorded Given the same policy and consumer provider blocking enabled When an authenticated requester has an email domain of gmail.com but gmail.com is explicitly allowlisted Then the download is allowed And an audit event records the explicit allow override and policy version Given a link that allows email-only verification (no SSO) When the requester has not completed email verification Then the download is blocked with HTTP 401 and error code EMAIL_VERIFICATION_REQUIRED And after successful verification, policy evaluation uses the verified email domain
Wildcard, Matching Semantics, and IDN Normalization
Given a policy with allowlist [*.partner.com] When the recipient domain is team.partner.com Then sharing is allowed Given the same policy When the recipient domain is partner.com (no subdomain) Then sharing is blocked with error DOMAIN_NOT_ALLOWED Given the same policy When the recipient domain is partnerx.com or team.partner.co Then sharing is blocked with error DOMAIN_NOT_ALLOWED Given a policy evaluation for an internationalized domain xn--bcher-kva.de (bücher.de) When the input is provided in Unicode or punycode with mixed case or a trailing dot Then the system normalizes to punycode, ignores case and trailing dot, and evaluates consistently And the audit event captures the normalized domain used for rule matching
Deterministic Precedence with Geo/IP and Time-Bound Exceptions
Given content download from an IP geolocated in a country on the blocked list And the requester domain is on the allowlist When the requester attempts access Then access is blocked with HTTP 403 and error code GEO_IP_DENY And geo/IP denial takes precedence over domain allow Given a policy with an explicit domain deny for leak.partner.com and an active exception window allowing leak.partner.com for 2 hours When a requester from leak.partner.com attempts access within the exception window Then access is allowed and the audit event records the exception ID and expiry timestamp Given the same policy When the requester attempts access after the exception window expires Then access is blocked with HTTP 403 and error code DOMAIN_DENY Given content flagged as ITAR/EAR-restricted When any external domain attempts access regardless of allowlist or exception Then access is blocked with HTTP 403 and error code REGULATORY_EXPORT_RESTRICTED And a compliance audit event is recorded Given multiple matching rules (wildcard allow and explicit deny) When evaluating a request Then the precedence order is: Regulatory/Geo-IP denies > Explicit domain denies > Time-bound exceptions > Allows > Default deny And the evaluation response includes the winning rule and precedence tier
Recipient Identity Validation via SSO Claims and Email Verification
Given federation is required for invites to enterprise domains When an invite is sent to alice@enterprise.com and the recipient authenticates with SSO whose verified domain is enterprise.com Then access is granted and recorded with identity provider, claim source, and policy version Given the same requirement When the recipient authenticates with SSO whose verified domain is corp.enterprise.com and the policy allows subdomain equivalence Then access is granted Given the same requirement When the authenticated SSO domain does not match the invite email domain and subdomain equivalence is not allowed Then access is blocked with HTTP 403 and error code DOMAIN_MISMATCH Given email-only verification is permitted by policy When the recipient completes email verification for bob@approved.com Then the system extracts the domain from the verified address and applies domain policy before granting access And invites remain pending until verification completes
Embedded Player Referrer Enforcement for Link-Based Access
Given referrer enforcement is enabled with referrer allowlist [learn.acme.edu, portal.partner.com] When a link-based playback request includes an HTTPS referrer of learn.acme.edu Then playback is allowed Given the same policy When a request has a missing or stripped referrer Then playback is blocked with HTTP 403 and error code REFERRER_REQUIRED unless allow_no_referrer is true Given the same policy When a request includes a referrer of attacker.com Then playback is blocked with HTTP 403 and error code REFERRER_DENY And the audit event logs the presented referrer and matched rule Given a referrer policy change When updated via UI or API Then enforcement behavior changes within 60 seconds across all edges And a versioned audit entry is created
Admin Policy Management, Versioning, Auditability, and Dry-Run Evaluation
Given an admin creates or updates a domain policy via UI or API When the change is saved Then a new policy version is created with version ID, actor, timestamp, and change diff (added/removed domains, wildcard patterns, consumer block toggle, exceptions) And the policy propagates to enforcement points within 60 seconds Given the audit log When queried by time range or policy version Then it returns entries with actor, action (create/update/delete/revert), affected resources, and outcome Given a dry-run evaluation endpoint When provided a sample target (share vs. download), recipient/requester identity, IP/geo, referrer, and timestamp Then it returns a deterministic evaluation including matched rules, precedence steps, and the final decision without performing the action Given a revert is requested to a prior version When the revert is confirmed Then the prior version becomes active with a new version ID and an audit event records the revert source and approver
ITAR/EAR Content Classification & Policy Binding
"As a compliance officer, I want potentially export-controlled content to be identified and automatically placed under stricter controls so that we reduce the risk of unlawful export."
Description

Introduces automated and manual tagging of assets that may be subject to ITAR/EAR or similar export controls. Uses AI-assisted classification backed by confidence scores and a mandatory human review workflow for high-risk detections. When content is flagged, the system binds enhanced restrictions (e.g., stricter geofencing, domain lockdown, and export disablement) and requires dual-approval to lift. Stores provenance of tags, reviewer actions, and policy versions. Integrates with ingestion, captions, summaries, and highlight generation to ensure derived assets inherit controls. Enforcement is performed at access time and during link creation, with complete audit trails for regulatory evidence.

Acceptance Criteria
AI Classification Thresholds & Human Review Trigger
Given an asset is ingested and the classifier returns ITAR/EAR with confidence >= the configured high-risk threshold, When processing completes, Then the asset is auto-flagged as ITAR/EAR-high-risk, enhanced restrictions are applied immediately, and the asset is placed in the mandatory human review queue. Given an asset returns ITAR/EAR with confidence < the high-risk threshold but >= the informational threshold, When processing completes, Then the asset is tagged as needs-review without enforcement and a review task is created for a human reviewer. Given thresholds are updated by an admin, When a new asset is ingested, Then the updated thresholds are applied and the effective thresholds and policy version are recorded in the audit log. Given an asset is in the review queue, When a reviewer confirms or rejects the classification, Then the final tag is set accordingly, enforcement is adjusted, and the decision, reviewer identity, and confidence score are stored in provenance.
Manual Tagging & Override Provenance
Given a user with Tag Manager permission opens an asset, When they manually apply an ITAR/EAR tag, Then enhanced restrictions take effect immediately, a justification is required, and provenance captures user, time (UTC), IP, justification, and policy version. Given a user attempts to remove an ITAR/EAR tag, When they submit the change, Then the system requires initiation of the dual-approval workflow and the tag remains enforced until approvals complete. Given provenance is requested, When viewing the asset’s compliance history, Then a chronological, non-editable list of all tag additions, removals, and overrides is displayed and can be exported to CSV/JSON.
Policy Binding at Access and Link Creation
Given an asset is flagged as ITAR/EAR, When a user from a prohibited country/region/IP or non-allowed domain attempts to view, download, share, or export highlights, Then access is blocked, download/export controls are disabled, and a clear compliance message with an event ID is shown. Given a user attempts to create a share link for a flagged asset, When the requested link settings violate geofence, domain allowlist, or data residency rules, Then link creation is prevented and the user is offered compliant settings (e.g., restrict to allowed domains/regions) to proceed. Given an allowed user within permitted region/domain accesses a flagged asset, When playback is permitted by policy, Then streaming is allowed but download/export actions remain disabled unless explicitly allowed by policy binding, and all decisions are logged.
Dual-Approval to Lift ITAR/EAR Restrictions
Given an asset is under ITAR/EAR restrictions, When an approver submits a request to lift restrictions, Then the system requires a second approval from a different eligible approver and prevents the requester from self-approving. Given the second approval is granted, When the change is finalized, Then restrictions are lifted, the justification and both approvers’ identities are recorded with timestamps and policy version, and notifications are sent to the requester and admins. Given the second approval is rejected or not received within the configured window, When the window lapses or rejection occurs, Then restrictions remain in force and the outcome is logged with reason.
Inheritance for Captions, Summaries, Highlights
Given a source asset is flagged ITAR/EAR, When captions, summaries, and highlight clips are generated, Then all derived assets inherit the ITAR/EAR tag and the same or stricter restrictions automatically. Given derived assets already exist when the source becomes flagged, When the flag is applied, Then derived assets are updated within 5 minutes to inherit restrictions and any active links that violate policy are invalidated. Given a derived asset is requested for export, When its source is flagged, Then export is blocked with a compliance message and an audit event is recorded including the derived asset ID and the source asset ID.
Immutable Audit Trail & Evidence Export
Given any classification, review decision, policy change, access attempt, or link action occurs, When the event is saved, Then an immutable audit record is created capturing asset ID, actor, action, outcome, timestamp (UTC), IP, geolocation (if available), policy version, and reason (if provided). Given an auditor requests evidence for a date range and asset set, When exporting audit logs, Then the system produces a signed CSV/JSON including a cryptographic hash per file to verify integrity and is downloadable within 30 seconds for up to 100k events. Given a user views an asset’s compliance history, When filtering by event type (classification, review, enforcement, access block), Then results return within 2 seconds for up to 10,000 events.
Preflight Share/Export Validation & Messaging
Given a user initiates creation of a share link or export for a flagged asset, When preflight checks run, Then the system validates geofence, domain allowlist, IP allow/deny, and data residency rules before any link or export artifact is created. Given any preflight check fails, When presenting results, Then no artifact is created, a consolidated error message lists each failed check with codes, and an audit event is recorded with the attempted settings. Given all preflight checks pass, When a link is created, Then the link includes embedded policy metadata (geofence, allowed domains, expiry) and the bound policy version is logged and displayed to the creator.
Data Residency-Aware Processing & Storage
"As a security architect, I want all ClipSpark processing and storage to remain within my chosen region so that we meet data residency obligations."
Description

Ensures that original videos and all derivatives (captions, summaries, highlight clips, transcripts, thumbnails) are stored and processed within the selected residency region. Routes AI processing jobs to regional workers, keeps encryption keys region-local, and prevents cross-region replication, CDN egress, or backups that violate policy. Supports intra-region HA/failover without leaving the region and provides migration tooling for compliant region changes with full audit. Honors per-tenant residency settings and integrates with geofencing to block exports that would cause residency breaches. Emits residency compliance events for monitoring and evidence.

Acceptance Criteria
Region-Locked Storage for Originals and Derivatives
Given tenant residency is set to "eu-west-1" and a 2GB video is uploaded When derivatives (captions, summaries, highlight clips, transcripts, thumbnails) are generated Then 100% of original and derivative objects exist only in "eu-west-1" storage with region metadata = eu-west-1 And any access via non-eu-west-1 endpoints returns 403 and logs zero cross-region egress bytes And the residency audit inventory for the tenant reports 0 non-compliant objects
Regional AI Processing Job Routing
Given tenant residency is set to "ap-southeast-2" When captioning, summarization, and highlight jobs are queued and executed Then jobs are scheduled only on workers labeled region=ap-southeast-2 and all service calls resolve to region-local endpoints And if regional capacity is exhausted, jobs enter status=WaitingCapacity within 2 seconds and are not routed to any other region And job telemetry includes region=ap-southeast-2 for all stages; any cross-region call attempt is blocked and logged as policy_violation
Region-Local Key Management and Access
Given tenant residency is set to "us-gov-west-1" When encrypting data at rest and performing decrypt operations during processing Then only KMS keys scoped to "us-gov-west-1" are used for encrypt/decrypt And key rotation and grants occur only within "us-gov-west-1" And decrypt operations using keys from any other region fail with 403 and emit a compliance_violation event
No Cross-Region Replication, Backup, or CDN Egress
Given tenant residency is set to "eu-central-1" When daily backups run and CDN serves protected media Then backup targets reside only in "eu-central-1" and backup metadata shows region=eu-central-1 And cross-region replication configurations are disabled for tenant namespaces And CDN responses for protected media include Residency-Region: eu-central-1 and any request requiring cross-region origin fetch returns 451 with error_code=RESIDENCY_BLOCK And network egress logs show 0 bytes to regions outside eu-central-1 for tenant content over a 24-hour window
Intra-Region High Availability and Failover
Given tenant residency is set to "eu-west-1" and an Availability Zone outage is simulated within the region When failover procedures trigger Then read/write operations resume within RTO ≤ 15 minutes with RPO ≤ 5 minutes And no components initiate cross-region traffic; outbound firewall counters to non-eu-west-1 remain at 0 And health dashboards show region=eu-west-1 for all active replicas during and after failover
Compliant Tenant Region Migration with Full Audit
Given a tenant requests migration from "eu-west-1" to "eu-central-1" with approval When the migration tool runs in dry-run mode Then it produces a plan including counts, sizes, and SHA-256 checksums per artifact type and an estimated cutover window When the migration executes Then transfers occur only between the source and target regions over TLS 1.2+; no third region is used; all access is logged with correlation_id And post-cutover, inventory and checksum parity equals 100%; old-region data enters 7-day quarantine and is then purged; audit log records who/when/what and signatures; user-visible downtime ≤ 30 minutes
Geofence Integration and Residency Compliance Events
Given tenant residency is set to "ap-south-1" and geofence rules block exports outside India When a user attempts to create a share link for a viewer in "us-east-1" or from a US IP Then the action is blocked with HTTP 403 and error_code=RESIDENCY_GEOFENCE_BLOCK; the link is not generated And a compliance event is emitted with fields: tenant_id, user_id, artifact_ids, residency_region=ap-south-1, attempted_destination=US, policy_id, action=blocked, timestamp, correlation_id And events are delivered to the monitoring sink within 2 minutes with at-least-once delivery; event retention ≥ 365 days; 100% of blocked attempts are captured in the audit trail
Admin Policy Console, Audit Trail, and Dry-Run Simulator
"As an administrator, I want to configure policies, simulate their impact, and review enforcement events so that I can enforce compliance confidently and prove it during audits."
Description

Delivers an admin console to create, edit, and publish geofence and domain policies using a guided rule builder with validation and precedence previews. Includes a dry-run simulator to test IPs, countries, regions, and domains before deployment, showing the exact decision path. Provides filterable, exportable audit logs of allowed/blocked events with reasons, user/link context, and policy versions. Supports RBAC (separate roles for view, edit, approve), change approvals, time-bounded exemptions, and retention controls. Integrates with SIEM via webhooks and standard formats (e.g., CEF) for real-time alerting and compliance reporting.

Acceptance Criteria
Policy Rule Builder—Validation and Precedence Preview
- Given I am assigned the Editor role, When I add or edit a rule using country, region, IP/CIDR, domain, and content tag (e.g., ITAR/EAR) conditions with Allow/Block actions, Then the UI validates syntax and value ranges in real time and displays inline errors that prevent Save until resolved. - Given at least two rules that could overlap, When I open Precedence Preview, Then the system shows the exact evaluation order and indicates which rule would take effect for a provided test input, including rule IDs and action (Allow/Block). - Given critical validation errors exist, When I attempt to Publish, Then the Publish action is disabled and a banner lists blocking issues; warnings allow Publish only after explicit confirmation. - Given a rule references an unknown country/region code or malformed domain, When I save, Then saving is blocked and the field is highlighted with a specific error message.
Dry-Run Simulator—Deterministic Decision Path
- Given draft and published policies exist, When I input an IP (v4/v6), country, region, domain, content tags, and optional evaluation time, Then the simulator returns a final decision (Allow/Block) together with policy version, matched rule ID(s), and evaluation timestamp. - Given any input set, When I run the simulation, Then a step-by-step decision path shows each evaluated rule with true/false outcome and the first-match that determines the decision. - Given a time-bounded exemption exists for the evaluated subject, When I set evaluation time inside the exemption window, Then the simulator shows Allow due to exemption and includes the exemption ID; When outside the window, Then the exemption is not applied. - Given I run simulations, When the page is refreshed, Then no production policy state is changed and no audit "real event" entries are created; a separate simulator activity log records runs.
Audit Logs—Capture, Filter, and Export
- Given any download/share request is allowed or blocked by policies, When the decision occurs, Then an audit record is written containing timestamp (UTC), user ID, content/link ID, decision, rule ID(s), policy version, IP, geolocation (country/region), domain, data residency region, and exemption ID (if applicable). - Given audit data exists, When I apply filters by date range, decision, user, domain, country, IP/CIDR, rule ID, policy version, or content tag, Then the results update within 2 seconds for up to 100k records. - Given filtered results, When I export, Then I can download CSV and JSON exports that include all selected columns and respect pagination to export the full filtered dataset. - Given retention is set to N days, When records exceed N days, Then they are automatically deleted or anonymized per configuration and no longer appear in UI or exports. - Given I have Viewer role, When I view logs, Then sensitive fields (e.g., last octet of IP) are masked; Given I have Editor or Approver role, Then full values are visible.
RBAC and Change Approval Workflow
- Given roles Viewer, Editor, and Approver exist, When a Viewer accesses the console, Then they can view policies, simulator, and logs but cannot create, edit, approve, or publish. - Given the same roles, When an Editor creates or edits a policy, Then they can save drafts and submit for approval but cannot publish. - Given a submitted change, When an Approver reviews it, Then they can approve or reject with a required comment, and the system records approver, timestamp, and diff. - Given an approved change, When Publish is executed, Then only an Approver can publish, and the policy version increments; all actions are logged in the audit trail. - Given an unapproved draft, When an Editor attempts to publish, Then the action is blocked with a clear error. - Given API access, When role tokens are used, Then the same permissions are enforced at the API layer.
Time-Bounded Exemptions Management
- Given a policy blocks a target (domain/IP/user/link), When an Approver grants an exemption for a defined subject and time window, Then the system records exemption ID, scope, start/end time, and reason. - Given an active exemption, When a matching request occurs within the window, Then the request is allowed and the audit record references the exemption ID and grantor. - Given the window expires, When subsequent requests occur, Then the exemption no longer applies and the original policy decision is enforced. - Given an exemption is revoked early, When future requests occur, Then they are evaluated as if no exemption exists. - Given the simulator, When I set evaluation time within the exemption window, Then the simulator shows the exemption being applied.
SIEM/Webhook Integration—Real-Time Alerts in CEF
- Given a SIEM endpoint and secret are configured, When an allow/block decision or policy publish occurs, Then the system sends a webhook within 10 seconds containing event type, decision, reasons, rule ID(s), policy version, user ID, content ID, IP, geo, domain, and exemption ID (if any). - Given SIEM format settings, When events are emitted, Then they are available in both JSON and CEF formats with correct field mappings and headers. - Given the endpoint is unavailable, When delivery fails, Then retries occur with exponential backoff up to 6 attempts; after final failure, a dead-letter log entry is created and an admin alert is shown. - Given signed delivery is enabled, When the SIEM validates the HMAC signature header, Then it can verify message authenticity using the shared secret. - Given an admin runs "Send Test Event," When the endpoint responds, Then the console displays success/failure with last response status and latency.
Data Residency and Storage Controls for Audit Data
- Given data residency is configured to region R, When audit records are written, Then they are stored in region R and exports are served from region R; cross-region transfer is blocked. - Given a user initiates an export from a region-disallowed location, When the request violates residency policy, Then the export is blocked and a clear error is shown and logged with rule ID/reason. - Given residency or retention changes, When new settings are saved, Then a confirmation warning is shown with impact summary, and changes are versioned and logged.
Compliance Gate on Share/Download Creation
"As a content owner, I want non-compliant links to be blocked at creation with clear guidance so that I don’t accidentally share restricted content."
Description

Adds a preflight compliance gate that evaluates geo, domain, and content-control policies at the moment a share link or download is created. Annotates links with signed, tamper-evident tokens carrying policy claims (expiry, geo/domain constraints) and enforces them on request. Provides user-friendly error messaging with remediation steps, optional justification capture, and an approval workflow for exceptions. Ensures parity across UI, API, and SDKs, including bulk operations. Supports immediate revocation and expiry updates, localized messaging, and comprehensive metrics on blocked vs. allowed attempts.

Acceptance Criteria
Preflight Gate on Share/Download Creation
- Given a user initiates share link creation or a downloadable export, when geo/country/region, IP range, domain allow/deny, data residency, and content classification (e.g., ITAR/EAR) policies apply, then the gate evaluates all applicable policies before any link/package is created. - When the request violates any applicable policy, then the operation is rejected with HTTP 403, errorCode=COMPLIANCE_BLOCKED, policyReasons enumerated, and no link/package identifier is persisted or returned. - When the request satisfies all applicable policies, then the operation succeeds and a link/package identifier is returned, and the decision is logged with outcome=allowed. - Gate decisions are deterministic and idempotent: repeating the same request within the same policy state yields the same outcome.
Signed Policy Token Issuance and Request-Time Enforcement
- Given a compliant share/download is created, when the system issues the access token, then the token is signed and tamper-evident and includes claims: linkId, expiry (ISO8601), allowedCountries/regions, allowedDomains, contentClassification, policyVersion. - When a request presents a token with any modified claim or invalid signature, then access is denied with HTTP 401, errorCode=TOKEN_INVALID, and the attempt is logged. - When a request presents an expired token, then access is denied with HTTP 401, errorCode=TOKEN_EXPIRED. - When a request originates from a disallowed IP/geo or referrer/domain not matching allowedDomains per token/policy, then access is denied with HTTP 403, errorCode=POLICY_ENFORCEMENT, and the policy reason includes which constraint failed. - When all token validations and active policy checks pass, then access is granted and the decision is logged with outcome=allowed.
Immediate Revocation and Expiry Update Propagation
- Given an admin revokes a share/download via UI or API, when the revocation is confirmed, then all subsequent access attempts for that link are denied within 60 seconds globally with HTTP 403, errorCode=REVOKED. - Given an admin updates the expiry for an existing link, when the new expiry is saved, then the new expiry is enforced on all subsequent requests within 60 seconds regardless of previously issued token claims. - Bulk revocation by asset, user, or policy reason is supported; each targeted link reflects revoked status within 60 seconds and emits an audit event. - Revocation and expiry updates do not require client-side cache clears; enforcement occurs server-side.
Parity Across UI, API, SDKs, Including Bulk Operations
- Given the same input and policy state, when a share/download is attempted via UI, REST API, or official SDKs, then the gate outcome, HTTP status (for API/SDK), errorCode, and policyReasons are consistent across channels. - Bulk create operations return a per-item result set with created=true/false, id (when created), and policyReasons (when blocked); non-compliant items are not created and do not affect compliant items. - SDKs call the same endpoints and surface the same error codes/messages; contract tests validate parity for at least share-create, download-initiate, revoke, and expiry-update. - Rate limits and retries do not bypass or defer compliance checks; retries preserve idempotency keys per item.
Localized, Actionable Error Messaging
- When an operation is blocked, then the UI displays a localized message per user locale with: concise reason, actionable remediation steps (e.g., request exception, try from allowed network/domain, contact admin), and a copyable requestId. - When localization for a locale is unavailable, then messages fall back to English without placeholder keys. - API/SDK responses include machine-readable errorCode and policyReasons plus a human-readable message key for localization on clients. - Error messages do not reveal sensitive policy internals (e.g., exact IP ranges) but include enough context to guide remediation.
Justification Capture and Exception Approval Workflow
- When a block occurs and the policy permits exceptions, then the user can submit a justification containing required fields: reasonCategory, freeText (<=500 chars), desired duration, and intended recipient domain (if applicable). - When an admin reviews a justification, then they can approve or deny; on approval, a time-bound exception is created with explicit scope (user, asset, action) and duration, and the previously blocked operation can complete while the exception is active. - When the exception expires or is revoked, then enforcement reverts immediately, and new attempts are blocked per policy. - All requests, decisions, and exception scopes are audit-logged with timestamps, actors, and rationale.
Compliance Metrics and Audit Logging
- For every gate decision and request-time enforcement, an event is recorded with: timestamp, userId, assetId, action (share|download|access), channel (UI|API|SDK), outcome (allowed|blocked), policyReasons, geo (country/region), ipHash/cidrBucket, domain/referrer, requestId. - Metrics endpoints/dashboards provide aggregates of allowed vs. blocked by time window, policy reason, channel, geo, and asset, with export to CSV/JSON. - Event ingestion achieves >=99.9% delivery to storage within 5 minutes; data is retained for at least 90 days and is accessible to admins with appropriate permissions. - Clock skew or late-arriving events do not double-count; idempotent event keys ensure accurate aggregates.

ClipGuard Links

Create expiring, SSO-gated, single-use links tied to a specific user. Overlay dynamic, identity-stamped watermarks (email, time, IP) and revoke access instantly from the dashboard—enabling safe external reviews without losing traceability.

Requirements

Identity-Bound Single-Use Links
"As a content owner, I want to send a link that only the intended reviewer can open once so that I can prevent uncontrolled sharing of my recordings."
Description

Generate cryptographically secure, single-use access links that are bound to a specific recipient identity (email) and a specific ClipSpark asset. Upon the first successful, authenticated access, the token is consumed and cannot be reused. Enforce one active session per link, reject concurrent or replay attempts, and record detailed access metadata (time, IP, user agent). Scope permissions to view-only streaming with no download, and ensure the link routes to the secure ClipSpark viewer with captions, summaries, and highlights available as configured. Provide server-side validation and tamper-proof signing to prevent parameter manipulation and link forgery.

Acceptance Criteria
Generate Single-Use Link Bound to Recipient Email and Asset
Given an authorized user selects a ClipSpark asset and enters a recipient email When they generate a single-use link Then the system creates a tokenized URL bound to exactly that asset ID and recipient email And the token has at least 128 bits of entropy and is unguessable And the binding is enforced server-side (no client-modifiable identifiers are trusted) And the link requires recipient authentication via an email-asserting IdP before any asset is served
First Authenticated Access Consumes Token
Given a recipient opens the link and authenticates as the exact email bound to the token When the server validates the signature, token state, and identity Then access is granted and the token state transitions to Consumed And any subsequent request using the same token returns 410 Gone with reason "TokenConsumed" And if the authenticated email does not match the bound email, access is denied with 403 Forbidden and the token remains Unconsumed
Prevent Concurrent Sessions and Replay
Given a valid, unconsumed link When two or more clients attempt to use it at the same time Then only the first validated session is established and marked Active And all concurrent attempts receive 409 Conflict with reason "ConcurrentSessionNotAllowed" And the token is marked Consumed upon first successful stream initialization And any reuse or refresh after consumption is treated as a replay and returns 410 Gone
Record Detailed Access Metadata
Given the first successful access occurs Then the system records: UTC timestamp (ISO 8601, ms precision), source IP, and user agent And the record includes token ID, asset ID, and authenticated email And the metadata is persisted to an audit log and is queryable by administrators And on denied or replay attempts, the same metadata plus a reason code is recorded
Enforce View-Only Streaming Without Download
Given a recipient has an active session from a consumed link When they use the ClipSpark viewer Then video/audio stream without any download control visible And any request to a download endpoint for the asset returns 403 Forbidden And HLS/DASH manifests and segments require session-bound authorization; unsigned requests return 401/403 And the viewer player does not expose browser-native download attributes
Server-Side Validation and Tamper-Proof Signing
Given a tokenized link signed over asset ID, recipient email, and token ID When any parameter is altered or the signature is missing/invalid Then the server rejects the request with 400/403 and does not disclose asset existence And tampering or forgery attempts never result in access or token consumption And all signature verification and authorization checks occur server-side
Route to Secure Viewer With Configured Modules
Given an asset has specific viewer modules enabled (captions, summary, highlights) When the recipient opens the valid link and is authenticated Then they are routed to the secure ClipSpark viewer for that asset And only the enabled modules are visible; disabled modules are hidden And only the bound asset is accessible; navigation to other assets is blocked
SSO Gate and Identity Verification
"As a security-conscious admin, I want link access to be gated by my organization’s SSO so that only verified identities can view sensitive content."
Description

Require recipients to authenticate via supported enterprise SSO providers (OIDC/SAML: Google, Microsoft, Okta) before accessing a ClipGuard link. Validate that the authenticated identity matches the email bound to the link; deny access on mismatch with an auditable reason. Support SP-initiated flows, IdP discovery, and just-in-time user provisioning for external reviewers. Handle token refresh, session timeout, and error states with clear messaging. Log identity claims (subject, issuer) for traceability while complying with privacy settings.

Acceptance Criteria
Access granted when SSO-authenticated identity matches bound email
Given a ClipGuard link bound to user@example.com and an active IdP configuration (Google OIDC, Microsoft OIDC, or Okta SAML) When the recipient authenticates and the asserted email claim equals user@example.com after normalization (trim, lowercase, Unicode NFKC) Then grant access within 2 seconds p95, render the protected content, and record an audit event with timestamp (UTC), provider, subject, issuer, link ID, and outcome=SUCCESS And Then if the IdP returns multiple email-related claims, the platform applies provider-specific mapping rules to select the primary email before comparison And Then set a session cookie (HttpOnly, Secure, SameSite=Lax) with expiry per org policy and tie it to the authenticated subject/issuer pair
Deny access and record auditable reason on email mismatch
Given a ClipGuard link bound to a@corp.com When the IdP assertion lacks an email claim or asserts b@corp.com (normalized) that does not equal the bound email Then deny access with HTTP 403 and display a user-safe message: "Access denied: identity does not match link" And Then do not load any protected content or metadata And Then create an audit event with outcome=DENY, reasonCode in {IDENTITY_MISMATCH, EMAIL_CLAIM_MISSING}, asserted identifiers (subject, issuer), and email recorded per privacy mode (raw in standard, salted hash in restricted) And Then subsequent retries require re-authentication and do not alter the audit history
SP-initiated SSO with IdP discovery and JIT provisioning for external reviewer
Given no existing user record for ext@partner.com and a ClipGuard link bound to ext@partner.com When the recipient opens the link Then perform IdP discovery using domain routing rules; if multiple IdPs match, present a selector and proceed with the chosen IdP And When authentication succeeds via Google OIDC, Microsoft OIDC, or Okta SAML in SP-initiated mode Then create a just-in-time user record with fields {email, subject, issuer, createdAt, external=true} and proceed to access evaluation without admin intervention And Then end-to-end latency from link open to content render is <= 6 seconds p95 And Then log both a PROVISION event and a subsequent ACCESS event correlated by request ID
Token refresh and session timeout behavior
Given an active authenticated session for a ClipGuard link When the access token is within 5 minutes of expiry and silent refresh is allowed Then refresh the session using the configured protocol (OIDC refresh token or SAML session re-auth) without interrupting playback; refresh completes within 1.5 seconds p95 And When refresh fails or silent refresh is disabled Then display a non-blocking banner "Session expiring—please re-authenticate" starting 60 seconds before timeout and preserve the return-to URL upon re-auth And Then enforce org-configured idle and absolute timeouts with ±2 minutes clock-skew tolerance; on timeout, redirect to SSO and invalidate app session And Then post-IdP logout, the next request requires re-authentication and no protected content is cached client-side
Error handling and user messaging for SSO failures
Given SSO failures such as IdP unreachable, invalid signature, assertion expired, clock skew, or user locked When the error occurs during link access Then present clear, user-safe messages mapped to machine-readable error codes (e.g., SAML_SIGNATURE_INVALID, OIDC_TOKEN_EXPIRED, IDP_UNAVAILABLE) without exposing sensitive details And Then provide Retry and Contact Admin actions where appropriate; transient errors implement exponential backoff (max 3 retries) with jitter And Then return appropriate HTTP statuses: 401 for unauthenticated, 403 for unauthorized/mismatch, 502/503 for IdP/network issues; include error code and correlation ID in JSON payload for API clients And Then record an audit event with outcome=ERROR and detailed reasonCode
Privacy-compliant identity logging and data minimization
Given org privacy modes {standard, restricted} When access is granted or denied for a ClipGuard link Then always log subject and issuer; in standard mode store raw email and full IP; in restricted mode store salted hash of email, mask IP (/24 IPv4, /48 IPv6), and omit user agent string if configured And Then each audit record contains eventType, timestamp (UTC), link ID, provider, correlation ID, outcome, and reasonCode (if not SUCCESS) And Then audit logs are immutable, queryable in the dashboard by link, outcome, provider, and exportable as CSV; access is RBAC-controlled And Then retention and purge follow org policy (default 90 days) and background purge removes PII per mode without breaking referential integrity
Dynamic Forensic Watermarking Overlay
"As a content owner, I want visible identity watermarks on the reviewer’s playback so that any captured footage remains traceable to the individual who accessed it."
Description

Overlay a dynamic, identity-stamped watermark on the video and transcript viewer that continuously renders the recipient’s email, current timestamp, and source IP. Use randomized drift, multi-position cycling, and opacity modulation to resist cropping and screen-recording while maintaining readability. Ensure low-latency rendering that does not degrade playback performance, supports dark/light modes, and adapts to various resolutions and DPR. Prevent client-side removal, and synchronize watermark state with session identity for end-to-end traceability in screenshots and recordings.

Acceptance Criteria
Watermark identity fields render and refresh on video and transcript
Given a user has an active session identity containing email and source IP And a video player and transcript viewer are loaded When playback starts or the transcript viewer becomes visible Then a watermark displays the user’s email, current timestamp with UTC offset, and source IP on both the video and transcript viewers And the timestamp value updates at least once per second And the source IP value updates within 5 seconds if the client’s public IP changes mid-session And the watermark remains visible within the viewport at all times without full occlusion by in-app UI elements
Dynamic drift, multi-position cycling, and opacity modulation
Given the watermark overlay is active with a session-specific randomness seed When 60 seconds of playback elapse Then the watermark has appeared in at least 6 distinct screen regions And position change intervals vary between 8 and 15 seconds (randomized per session) And continuous drift magnitude varies between 1% and 3% of the shorter viewport dimension per second And opacity modulates between 15% and 35% And text remains readable at all times with a measured contrast ratio of at least 3:1 against the underlying content in both light and dark modes
Cropping and screen-recording resilience
Given a 30-second on-screen capture or external screen recording at any common aspect ratio (including 16:9 and 4:3) And up to 20% cropping is applied from any edge during or after capture When the recording is reviewed frame-by-frame Then at least 90% of frames contain a visible and legible portion of the watermark that includes identity (email or IP) and a timestamp And within the 30-second interval the watermark is present in at least 5 distinct positions And watermark text height in the captured frames is at least 14 CSS px equivalent
Low-latency rendering and playback performance
Given baseline playback metrics are collected for a 1080p60 video without the overlay When the watermark overlay is enabled under the same conditions on a mid-tier device Then average per-frame render overhead added by the overlay is ≤ 2 ms And dropped frames increase by no more than 1 percentage point over baseline And first watermark paint occurs within 150 ms after the player signals ready And after a seek or playback-rate change, the watermark re-synchronizes its position and identity within 100 ms And additional memory usage attributable to the overlay is ≤ 20 MB
Dark/light mode support and multi-resolution/DPR adaptability
Given the application theme toggles between light and dark modes When the theme changes during playback Then the watermark palette adjusts automatically to maintain a contrast ratio ≥ 3:1 with underlying content And on displays with DPR in the range [1.0, 3.0], text renders without clipping or bitmap blurring And at 720p, 1080p, 1440p, and 4K resolutions, the watermark text scales to between 1.0% and 1.8% of the shorter video dimension, clamped to 12–28 CSS px And the watermark maintains at least an 8 px clearance from system captions, controls, and transcript UI elements
Client-side removal prevention and tamper response
Given a user attempts to hide or alter the watermark via DOM, CSS, or canvas manipulation When opacity is reduced below 0.1, visibility/display is toggled off, the element is moved off-screen, filtered to obscure text, or the overlay node/canvas is removed or replaced Then playback pauses within 2 seconds and the session is marked as tampered And access is revoked until the page is refreshed and the user re-authenticates And an audit log entry is recorded with user id, email, IP, timestamp, and a tamper reason code And repeated tamper attempts are rate-limited and do not crash or hang the application
Session synchronization and auditability across viewers and exports
Given the user re-authenticates or the SSO session identity changes mid-session When the new identity is established Then the watermark’s email, timestamp, IP, and session ID update within 2 seconds on both the video player and transcript viewer And both viewers display identical identity values and the same session ID at all times And any frames exported via in-app export or one-click highlight generation include the current watermark burned into the media And all identity changes and watermark state transitions are written to the audit log with precise timestamps and session IDs
Instant Revocation and Session Kill
"As an admin, I want to revoke access instantly so that I can stop unauthorized or unintended viewing the moment a risk is detected."
Description

Enable immediate revocation of any ClipGuard link from the dashboard, invalidating tokens within seconds across edge caches and active sessions. Force-disconnect live viewers, display an access-revoked screen, and block future attempts with a clear reason code. Record the revocation event, actor, timestamp, and the affected sessions for audit purposes. Provide API support for automated revocations and ensure idempotent operations to avoid inconsistent states.

Acceptance Criteria
Dashboard Revocation of ClipGuard Link
Given an admin user is viewing a valid ClipGuard link in the dashboard with at least one active session When the user clicks "Revoke link", selects a reason_code, and confirms Then the link status updates to "Revoked" in the dashboard within 2 seconds (p95) and 4 seconds (p99) And the UI disables further revoke actions for that link and shows a confirmation toast including the reason_code And any subsequent click on "Revoke link" returns a no-op response (200) with the original revocation metadata (idempotent)
Global Token Invalidation and Edge Cache Purge SLA
Given requests for the link token may be served from any CDN edge or the origin When the link is revoked at time T0 Then all CDN edges stop serving cached content for that token and return HTTP 403 with body.reason_code = "LINK_REVOKED" within 5 seconds (p95) and 10 seconds (p99) And the origin denies the token immediately (<= 1 second) after T0 And no endpoint in ClipGuard scope returns 2xx for the revoked token after T0 + 10 seconds
Active Session Kill and Access-Revoked Experience
Given one or more active viewers are connected via HLS/DASH or WebSocket using the link token When the link is revoked Then all active media/data sessions are terminated within 3 seconds (p95) and 6 seconds (p99) And clients receive a final Access-Revoked payload including reason_code and revocation_timestamp (UTC ISO-8601) And the player UI replaces playback with an Access Revoked screen preventing further seeking or downloading And any automatic reconnection attempts are denied with HTTP 403 and the same reason_code
Audit Logging and Traceability
Given a revocation occurs When the event is processed Then an immutable audit record is persisted containing: link_id, actor_user_id, actor_email, actor_ip, reason_code, revocation_timestamp (UTC), correlation_id, previous_status, affected_session_ids, affected_ips, user_agents And the record is queryable in the dashboard and via GET /api/v1/clipguard/links/{link_id}/audit within 10 seconds of T0 And subsequent operations do not modify the original audit entry (append-only), and any reads reflect a consistent, signed checksum or version
Automated Revocation API and Idempotency
Given a client calls POST /api/v1/clipguard/links/{link_id}/revoke with Idempotency-Key header and a reason_code When the request is retried 0–5 times within 24 hours using the same Idempotency-Key Then each response is 200 with the same revocation_id, revocation_timestamp, and reason_code, and no duplicate side effects occur And if the link is already revoked, the response is 200 with status = "already_revoked" and original revocation metadata And concurrent revoke requests with different Idempotency-Keys result in exactly one revocation event; others return 200 with status = "already_revoked"
Block Future Access Attempts With Clear Reason
Given the link is revoked When any party attempts access via the link URL, embedded player, API, or previously issued session tokens Then all requests are denied with HTTP 403 and a machine-readable reason_code matching the stored revocation reason plus a user-friendly message And responses include Cache-Control: no-store and are not cached by edges or clients And SSO re-authentication cannot reauthorize access to the revoked link; attempts result in the same 403 with reason_code And the dashboard displays the last denied attempt with timestamp, IP, and user identity when available
Security Coverage Across Artifacts and Derivatives
Given the link previously allowed access to captions, transcript, summaries, downloadable media, and highlight clips When the link is revoked at time T0 Then all derivative endpoints and download URLs tied to the token are invalidated under the same SLA as primary playback (<= 5s p95, <= 10s p99) And any pre-signed URLs issued before T0 return HTTP 403 within 10 seconds (p99) And after T0 no more than 1 MB of additional media is transferred per active session before termination
Expiration Policies and Link Lifecycle
"As a project manager, I want to set clear expiration windows for reviewer links so that access naturally ends without manual follow-up."
Description

Allow configurable link lifetimes (e.g., hours or days), start/end windows, and optional absolute expiry regardless of usage. Support pre-expiry reminders, one-click extensions, and policy presets (e.g., 24h single-use, 7-day window). Enforce server-side expiry, handle timezone normalization, and display clear status (active, consumed, expired) in the dashboard. Clean up expired links automatically while retaining essential audit logs per retention policy.

Acceptance Criteria
Configure Lifetime, Window, and Absolute Expiry Policy Presets
Given a policy preset "24h single-use" is selected When a link is created Then the link usage limit is 1 and effectiveExpiry = createdAt + 24h (UTC) Given a policy preset "7-day window" is selected When a link is created Then startAt = createdAt (UTC) and endAt = createdAt + 7 days (UTC) Given a custom lifetime value L in hours or days is entered When the link is created Then effectiveExpiry = createdAt + L (UTC) and invalid/unsupported units or out-of-range values are rejected with a validation error code LIFETIME_INVALID Given startAt S and endAt E are provided in any timezone When the link is saved Then S and E are normalized to UTC and saving fails with error WINDOW_INVALID if E <= S Given absoluteExpiry A is provided alongside lifetime and/or window When the link is created Then effectiveExpiry = min(A, endAt if set, createdAt + lifetime if set) and the applied precedence is recorded in the link metadata
Pre-Expiry Reminder Notifications
Given reminder offsets are configured for a policy (e.g., 24h and 1h before effectiveExpiry) When currentTime reaches effectiveExpiry - offset Then a reminder notification is queued to the link owner with the link name and localized expiry time Given a reminder has been queued When the link is revoked or already expired before send time Then the reminder is canceled and a cancellation event is logged Given a reminder was sent When viewing audit events Then a REMINDER_SENT record exists with linkId, recipient, scheduledAt, sentAt, and offset Given effectiveExpiry changes (e.g., via extension) When reminders exist Then prior reminders are rescheduled to the new effectiveExpiry and no duplicate reminders are sent for the same offset
One-Click Extension of Link Expiry
Given a link is Active or Expired and not constrained by absoluteExpiry When the owner clicks "Extend" in the dashboard Then effectiveExpiry is increased by the policy default increment or to the selected datetime and the new value is saved in UTC Given absoluteExpiry A is set When the owner attempts to extend beyond A Then the action is blocked with error EXTENSION_BEYOND_ABSOLUTE and no changes are persisted Given an extension is applied When viewing audit logs Then an EXTENSION_APPLIED record exists with previousExpiry, newExpiry, actorId, timestamp, and reason Given reminders were scheduled before extension When the extension is saved Then reminders are recalculated to the new effectiveExpiry Given a non-owner/non-admin attempts extension When the request is processed Then the server returns 403 FORBIDDEN and no changes are made
Server-Side Single-Use Consumption and Expiry Enforcement
Given a single-use link is Active within its availability window When the intended recipient accesses the link Then the server returns 200 OK, marks the link as consumedAt = now (UTC), and records consumer identity (userId or email, IP) Given a link has been marked consumed When any subsequent access is attempted Then the server returns 410 GONE with error LINK_CONSUMED and logs the attempt Given currentTime is before startAt When the link is accessed Then the server returns 403 FORBIDDEN with error LINK_NOT_ACTIVE_YET Given currentTime >= effectiveExpiry When the link is accessed Then the server returns 410 GONE with error LINK_EXPIRED regardless of client clock or cache state Given multiple concurrent access attempts occur on a single-use link When processed by the server Then at most one request succeeds and all others receive LINK_CONSUMED due to atomic consumption enforcement
Dashboard Status and Timezone Normalization
Given a link exists with startAt, effectiveExpiry, and consumedAt null When currentTime is within [startAt, effectiveExpiry) Then the dashboard shows status = Active and displays start/end in the viewer's selected timezone with a UTC tooltip Given a link has consumedAt set and currentTime < effectiveExpiry When the dashboard loads Then status = Consumed and the consumedAt timestamp is shown with consumer identity Given currentTime >= effectiveExpiry When the dashboard loads Then status = Expired and the exact expiry timestamp is shown Given a link spans a daylight saving transition When times are rendered Then displayed local times remain correct per the selected timezone rules and stored values remain in UTC Given a user changes their timezone preference When the dashboard reloads Then all displayed times re-render accordingly with no change to stored UTC values
Automated Cleanup and Audit Log Retention
Given a scheduled cleanup job runs periodically When it finds links with currentTime >= effectiveExpiry Then it deactivates and deletes access tokens/secrets for those links and marks them as archived without removing audit records Given cleanup has archived an expired link When querying the dashboard default view Then the link no longer appears in Active lists but remains discoverable via an "Include archived" filter or audit reports Given audit log retention policy R is configured When currentTime reaches expiredAt + R Then audit entries older than R are purged or anonymized per policy and the purge is logged Given an archived link with retained audit When exporting audit data Then the export includes linkId, ownerId, createdAt, expiredAt, consumedAt (if any), lastAccess IPs, and extension/reminder events, but excludes the deleted access token
Access Analytics and Anomaly Alerts
"As a security analyst, I want real-time visibility and alerts on link access patterns so that I can identify and respond to suspicious activity promptly."
Description

Capture detailed access telemetry (success/failure, IP, geolocation, device, browser), visualize it in the dashboard, and expose exportable audit logs. Detect anomalies such as multiple IPs in short windows, unexpected geolocations, repeated uses after consumption, or SSO mismatches, and trigger configurable alerts (email/slack/webhook). Provide per-link and aggregate views to help owners assess risk and take action quickly.

Acceptance Criteria
Access Telemetry Capture
Given a ClipGuard link is accessed by any client When the request completes (success or failure) Then exactly one access event is logged with fields: link_id, user_id/email (if known), outcome (success|failure), failure_reason (if failure), timestamp (UTC ISO 8601), IP address, geolocation (country, region, city), device type, browser name/version, OS And the event is queryable in the analytics dashboard within 2 seconds of request completion And SSO metadata (sso_provider, sso_subject) is recorded when SSO is used
Per-Link Analytics Visualization
Given an owner opens a link's Analytics page When the page loads Then a table/timeline of access events for that link is displayed with timestamp, outcome, IP, country, device, browser, and failure_reason And aggregates are shown: total attempts, success rate, unique IPs, unique devices, failures by reason, last access time And filters (date range, outcome, country, device, browser) update results within 2 seconds for up to 10,000 events And from any event row the owner can revoke the link; subsequent access attempts fail immediately and are logged
Workspace Aggregate Analytics
Given an owner opens the workspace Analytics view When the page loads Then aggregate metrics across all links for the selected date range are displayed: total attempts, anomalies by type, top links by activity, geolocation distribution And clicking any aggregate widget applies the corresponding filters and opens the detailed view in one click And all queries complete within 3 seconds for up to 100,000 events
Audit Log Export
Given filters are applied on the analytics view When the owner exports audit logs as CSV or JSON Then the exported file contains exactly the events matching the filters and includes fields: link_id, user_id/email, outcome, failure_reason, timestamp (UTC), IP, country, region, city, device, browser, OS, sso_provider, sso_subject (when present) And exports up to 100,000 rows complete within 10 seconds; larger exports stream in chunks with pagination tokens And an export event is recorded with requester identity, time, filter summary, and format
Anomaly Detection — Multiple IPs in Short Window
Given the rule "Multiple IPs in Short Window" is configured with threshold N=3 and window W=15 minutes When more than N distinct IPs access the same link within W Then an anomaly event is created containing link_id, distinct IPs, timestamps, N, W, and severity And alerts are delivered to all configured channels (email, Slack, webhook) within 60 seconds and include a deep link to the anomaly detail And duplicate alerts for the same link and rule are suppressed for 10 minutes
Anomaly Detection — Unexpected Geolocation
Given an allowed countries list is configured for a link or workspace When an access originates from a country not on the allowed list Then an anomaly event "Unexpected geolocation" is created with link_id, IP, country code, and timestamp And an alert is delivered to configured channels within 60 seconds with details and a deep link And the owner can add the country to the allowed list from the alert/dashboard, suppressing future alerts for that country
Anomaly Detection — Policy Violations (Reuse and SSO Mismatch)
Given a single-use link has already had a successful access When any subsequent access attempt occurs Then the attempt is blocked, logged with outcome=failure and failure_reason=Consumed, and an anomaly event "Repeated use after consumption" is created And alerts are delivered to configured channels within 60 seconds with details and a deep link Given a link is bound to user identity U via SSO When an access attempt presents SSO identity V where V != U or no SSO assertion is present Then the attempt is blocked, logged with outcome=failure and failure_reason=SSO_Mismatch, and an anomaly event "SSO identity mismatch" is created And alerts are delivered to configured channels within 60 seconds with details and a deep link
Admin Dashboard Link Management UI
"As a team admin, I want an intuitive UI to create and manage secure reviewer links so that I can control access without relying on engineering."
Description

Provide a streamlined dashboard to create, configure, and manage ClipGuard links: select assets, specify recipient identity, set expiry and policies, choose SSO requirements, and enable watermark options. Support bulk creation (CSV/import), quick copy, search/filter, and status badges (active, consumed, revoked, expired). Include per-link detail pages with timeline, access history, and revoke/extend actions, governed by role-based permissions.

Acceptance Criteria
Single Link Creation with SSO, Expiry, Watermark, and Quick Copy
- Given I have Create permissions and at least one asset exists, When I open the Create ClipGuard Link form, Then the form displays fields for Asset (required), Recipient (email, required), Expiry (date-time, required), Single-use (default on), SSO requirement (selectable), and Watermark options (toggle + tokens). - Given the form is empty, When I attempt to submit without required fields, Then inline validation errors appear and submission is blocked. - Given I enter a past expiry timestamp, When I submit, Then I see a validation error stating expiry must be in the future and submission is blocked. - Given SSO requirement is set to a provider, When I submit, Then the created link stores the SSO requirement and displays an SSO badge in the list. - Given Watermark is enabled with identity tokens, When I open Preview, Then I see a dynamic watermark preview including recipient email and current time placeholder. - Given the form is valid, When I click Create, Then the link is created, appears in the table within 2 seconds with status Active, shows expiry timestamp, SSO and Watermark badges, and creator name. - Given the link row is visible, When I click Copy Link, Then the link URL is copied to clipboard and a success toast appears.
Bulk Creation via CSV Import
- Given I have Create permissions, When I open Bulk Create and download the CSV template, Then the template includes headers: asset_id, recipient_email, expiry_iso8601, sso_provider(optional), watermark_enabled(optional). - Given I upload a CSV with N rows, When validation runs, Then I see a preview with counts of Valid, Invalid, and Duplicates by recipient+asset. - Given some rows are invalid (e.g., bad email, missing asset, past expiry), When I proceed, Then creation is blocked and I can download an error report CSV listing row numbers and reasons. - Given all rows are valid, When I confirm Create, Then the system creates links in bulk, shows a completion summary (created count, failed count=0), and lists new links in the table with correct badges and expiries. - Given a mixed-valid CSV, When I confirm Create, Then valid rows are created, invalid rows are skipped, and I can download a result report with per-row status. - Given bulk creation completed, When I search for a recipient from the CSV, Then newly created links are discoverable immediately.
Search and Filter Links in Dashboard
- Given there are 50+ links, When I type at least 2 characters in the search box (asset title or recipient email), Then the list updates within 300 ms to show matches and highlights the matched term. - Given I select filters (Status: Active/Consumed/Revoked/Expired; SSO: Any/Provider; Watermark: On/Off; Creator), When I apply them, Then only matching links are shown and a chip summary of active filters appears. - Given filters are active, When I click Clear All, Then filters reset and the full list returns. - Given the query yields no results, When the list renders, Then an empty state is shown with a Reset Filters action. - Given pagination is enabled, When I navigate pages while filters are applied, Then filters persist across pages.
Status Badges and Automatic Transitions
- Given a link is newly created, When it appears in the table, Then it shows the Active badge with tooltip and expiry timestamp in workspace timezone. - Given a recipient successfully accesses a single-use link, When the first access completes, Then the link status updates to Consumed and the badge changes within 5 seconds or on refresh. - Given an admin revokes a link, When revoke succeeds, Then the status changes to Revoked immediately and the badge reflects Revoked with the revoker and timestamp in tooltip. - Given a link reaches its expiry time, When the dashboard is refreshed or real-time update arrives, Then the status changes to Expired and the badge reflects Expired. - Given a link is Consumed or Expired, When I open the actions menu, Then Revoke is disabled and a tooltip explains why (already consumed/expired).
Per-Link Detail Page: Timeline and Access History
- Given I have View permissions, When I open a link’s detail page, Then I see header metadata (asset, recipient, expiry, status, SSO requirement, watermark state, creator) and a unique link ID. - Given the detail page loads, When I view the Timeline tab, Then I see a reverse-chronological event list including Created, Access Allowed/Denied (with reason), Consumed, Revoked, and Extended with timestamps and actor/SSO provider/IP. - Given there are >25 events, When I scroll, Then events are paginated or infinitely loaded without layout shift. - Given I need to export audit data, When I click Export CSV on the Timeline, Then a CSV downloads containing all events with fields: timestamp, event, actor, ip, user_agent, reason. - Given the link has been accessed, When I view Access History, Then I see the first successful viewer identity (from SSO) matching the recipient and all attempts with outcome and IP.
Revoke and Extend Actions from Detail Page
- Given I have Manage permissions, When I click Revoke on a non-expired link and confirm in the modal, Then the link status changes to Revoked, a success toast appears, and a Revoke event is added to the timeline. - Given a link is revoked, When a recipient tries to open the original URL, Then access is denied immediately and the attempt appears in Timeline as Access Denied (revoked). - Given a link is Active or Expired, When I choose Extend, select a new expiry later than now and later than the previous expiry, Then the new expiry is saved, status updates accordingly (Active if now < new expiry), and an Extended event is logged. - Given I enter an invalid extension (past time or <= current expiry), When I submit, Then validation prevents save and shows an error message. - Given I extend a Consumed link, When I save a new expiry, Then status remains Consumed and a timeline event notes extension on a consumed link.
Role-Based Permissions for Link Management
- Given roles exist (Owner/Admin/Editor/Viewer), When a Viewer signs in, Then they can view lists and details but cannot create, revoke, extend, or bulk import (actions hidden and API blocked). - Given an Editor signs in, When they view links, Then they can create new links and manage (revoke/extend/edit) only links they created; restricted actions on others are disabled with explanatory tooltips and enforced by API. - Given an Admin or Owner signs in, When they use the dashboard, Then they can create, bulk import, revoke, extend, and edit any link. - Given a user without permission calls a protected action (via UI or direct API), When the request is sent, Then the server returns 403 and the UI shows an authorization error and no state changes. - Given audit logging is enabled, When any privileged action is performed, Then the actor’s role and user ID are recorded and visible in the link timeline.

Audit Ledger

Capture a tamper-evident, cryptographically chained history of access, exports, and policy changes. Generate one-click audit packs and stream logs to your SIEM—accelerating investigations and proving compliance with minimal effort.

Requirements

Tamper-evident Append-only Ledger
"As a security and compliance officer, I want an immutable, tamper-evident ledger of all access, export, and policy-change events so that I can prove chain-of-custody and detect any manipulation."
Description

Implement a per-tenant, append-only audit ledger where each event is hashed and chained (e.g., SHA-256) with signed block headers and monotonic timestamps. Persist blocks to immutable storage (e.g., WORM/S3 Object Lock) with periodic checkpoints and published daily chain roots. Integrate writes across all event sources (web app, API, background jobs) with idempotency, deduplication, and gap detection. Provide observability (metrics/alerts) for write failures and chain anomalies. Outcome: provable, tamper-evident history of access, exports, and policy changes that underpins compliance and forensic workflows within ClipSpark.

Acceptance Criteria
Hash-Chained Append-only Event Write
Given a tenant with an existing ledger tail Hn When a new audit event is submitted from the web app, API, or background job Then the system computes Hn+1 using SHA-256 over {prevHash=Hn.hash, eventHash, seq, ts, tenantId} and sets seq=Hn.seq+1 and ts>Hn.ts And persists the event and Hn+1 atomically And returns 201 with {tenantId, seq, ts, headerHash} And a read of the ledger tail returns headerHash within 1 second And any attempt to update or delete an existing block is rejected with 409 and logged as a security event
WORM Persistence and Retention Enforcement
Given a committed block payload and header When persisting to storage Then the objects are written to an S3 bucket with Object Lock in Compliance mode and retention >= tenant-configured days (default 365) And the write is acknowledged only after checksum verification and a versionId is returned And subsequent delete or overwrite attempts before retention expiry fail with ObjectLocked/AccessDenied And bucket policy denies bypass of Object Lock and requires SSE-KMS encryption
Daily Chain Root Publication and Signed Checkpoints
Given ledgers for all tenants When the daily job runs at 00:05 UTC Then a chain root (hash of last block from genesis) is computed per tenant, signed with the service key, and published to an immutable location with {date, tenantId, root, signature} And verification from genesis or the latest signed checkpoint reproduces the published root And checkpoints are emitted at least every 10,000 events, each signed and linked, enabling O(log n) verification from checkpoint to tail And any mismatch during verification creates a P1 alert within 2 minutes and halts further publication for that tenant
Idempotent Writes, Deduplication, and Cross-Source Consistency
Given an incoming event carrying an idempotency key (Idempotency-Key or sourceEventId) When the same key is submitted multiple times within 7 days from any source (web, API, jobs) Then exactly one ledger block exists for that key and subsequent submissions return 200/201 with the original {seq, headerHash} And at-least-once delivery yields no duplicate blocks across sources And deduplicated attempts are counted in a metric (ledger_dedup_count) And if a sequence gap is detected (missing seq for >60 seconds after a commit), an alert is raised and an automated backfill retry is attempted
Monotonic Timestamps and Clock Skew Handling
Given a tenant ledger with last server timestamp ts_last When a new event arrives with source timestamp ts_src <= ts_last Then the block is written with server timestamp ts = ts_last + 1ms and annotated with {sourceTs=ts_src, skewMs=ts - ts_src} And if skewMs > 5 seconds, increment a metric and emit a warning log with correlationId And all blocks for a tenant exhibit strictly increasing server timestamps
Observability and Chain Anomaly Alerting
Given production operation When monitoring the ledger service over rolling 5-minute windows Then ledger_write_success_rate >= 99.9% and p95_write_latency <= 200ms and chain_verification_errors == 0 And if success_rate < 99% for 5 minutes, trigger a Sev-2 alert And on any chain break (prevHash mismatch, signature invalid, checkpoint/root mismatch), trigger a Sev-1 page within 2 minutes including tenantId and last good seq And dashboards expose tail seq, last checkpoint age, daily root publication status per tenant
Unified Audit Event Schema
"As a platform engineer, I want a consistent, versioned audit event schema across all services so that investigators and downstream tools can reliably parse and correlate events."
Description

Define a versioned, extensible audit event schema covering actor, action, target, tenant, resource_type (video, caption, summary, highlight), resource_id, outcome, error, ip, user_agent, auth_method, role, request_id, trace_id, geo, timestamp, and policy context. Enumerate and instrument all event types (views, downloads/exports, share-link creation, caption edits, summary generation, highlight creation, policy/role changes, API key lifecycle, SSO changes). Include data minimization and optional anonymization (e.g., IP truncation, hashed identifiers) with per-tenant configuration and backward compatibility. Provide a schema registry, validation, and migration strategy to ensure consistent ingestion, querying, SIEM mapping, and future-proofing across ClipSpark services.

Acceptance Criteria
Schema Versioning and Registry Enforcement
Given a valid audit event with schema_version vX When validated against the registry Then it is accepted and validation completes within 50 ms p95. Given an audit event missing any required field When validated Then it is rejected with error_code="SCHEMA_VALIDATION_FAILED" and error_path indicating the missing field. Given schema version vX+1 is registered When services continue emitting vX Then vX events are accepted and a deprecation_notice event is recorded. Given the migration tool is run to transform vX to vX+1 over ≥10,000 events When completed Then 100% of events are transformed with no field loss and source_count equals target_count.
Mandatory Fields and Enum/Type Validation
Given any audit event When validated Then the following fields are present and non-empty: schema_version, actor.id OR actor.hashed_id, action, target, tenant.id, resource_type, resource_id, outcome, timestamp. Given resource_type When validated Then it must be one of ["video","caption","summary","highlight"]. Given timestamp When validated Then it conforms to ISO 8601 UTC (e.g., 2025-09-13T12:34:56.789Z) and is not more than 5 minutes in the future. Given fields role, auth_method, outcome When validated Then they match allowed enumerations registered in the schema; non-conforming values are rejected. Given ip When validated Then if present it matches IPv4 or IPv6 format; if anonymized, it matches the configured truncation mask.
Event Enumeration and Instrumentation Coverage
Given each enumerated action (view, download/export, share-link creation, caption edit, summary generation, highlight creation, policy/role change, API key lifecycle, SSO change) occurs When exercised end-to-end Then one audit event per action is emitted and ingested with the correct action name and resource_type, with ≤1% duplicates and ≤0.1% missing over 10,000 actions per type. Given an action is blocked by policy When attempted Then an audit event is emitted with outcome="denied" and policy_context includes rule_id and decision="deny". Given an action fails due to system or user error When attempted Then an audit event is emitted with outcome="failure" and error.code and error.message populated.
Per-Tenant Data Minimization and Anonymization Controls
Given tenant anonymization=ON with IPv4 /24 and IPv6 /48 truncation When events are produced Then ip is stored as the truncated subnet and user_agent is hashed with a tenant-specific salt. Given tenant anonymization=OFF When events are produced Then full ip and user_agent values are stored. Given tenant actor_identifier_mode=HASHED When events are produced Then actor.hashed_id is populated, actor.id is omitted, and actor.pseudonymized=true. Given tenant updates minimization/anonymization settings When saved Then changes apply to new events only and an audit event is recorded for the configuration change. Given anonymization=ON When events are mapped to SIEM Then anonymized fields remain anonymized (no raw values present).
Cross-Service Correlation and Traceability
Given distributed tracing is enabled When an event is emitted Then request_id (UUIDv4) and trace_id (32-hex W3C trace id) are present and consistent across all events for the same request. Given querying by request_id When executed Then all related events across services are returned in ascending timestamp order with inter-service ordering jitter ≤200 ms. Given an incoming event lacks both request_id and trace_id When validated Then it is rejected with error_code="MISSING_CORRELATION_IDS".
SIEM Mapping and Streaming Compatibility
Given an audit event When streamed to the SIEM sink Then it is transformed per the registered SIEM mapping version and ingested with 0% mapping errors over a 10,000-event sample. Given per-tenant configuration When events are streamed Then tenant.id and schema_version are preserved as indexed fields in the SIEM output. Given anonymization settings are enabled When mapping occurs Then no step reintroduces raw identifiers or full IPs for anonymized fields.
One-click Audit Pack Generator
"As a compliance lead, I want to generate a complete, verifiable audit pack with one click so that I can respond to auditor requests quickly without engineering support."
Description

Build an on-demand generator that compiles a complete audit pack for a selected time window and scope (tenant, user, resource). Package includes executive summary, event statistics, anomalies, access and export timelines, policy change timeline, raw logs (JSONL/CSV), integrity proofs (hash-chain checkpoints and signatures), verification instructions, and control mappings (SOC 2, ISO 27001, HIPAA). Export as a signed ZIP with configurable PII redaction and an expiring share link. Runs as an asynchronous job with progress UI, notifications, rate limits, and audit of the export action itself. Integrates with the ledger, schema registry, and object storage.

Acceptance Criteria
Content Completeness for Selected Scope and Time Window
Given a valid request specifying scope (tenant|user|resource) and an ISO 8601 start and end time When the audit pack generation job completes successfully Then the exported ZIP contains: executive_summary.(pdf|html), event_statistics.json, anomalies.json, access_timeline.csv, export_timeline.csv, policy_change_timeline.csv, raw_logs.jsonl, raw_logs.csv, integrity_proofs.json, verification_instructions.txt, control_mappings.json And each included file is non-empty and UTF-8 encoded And raw_logs.jsonl and raw_logs.csv have identical record counts And all records and timeline entries fall within the specified time window and scope And event_statistics.json totals equal the number of raw log records for the given scope and time window And control_mappings.json includes mappings for SOC 2, ISO 27001, and HIPAA with framework/version metadata
Integrity Proofs and Signature Verification
Given the exported ZIP, the platform public verification key, and integrity_proofs.json When verification is performed following verification_instructions.txt Then the ZIP signature validates successfully against the platform public key And the hash-chain checkpoints in integrity_proofs.json match recomputed hashes of the included raw log segments for the selected time window And the first and last hash-chain checkpoints align with the earliest and latest included events, respectively And modifying any included file causes signature or hash-chain verification to fail
Configurable PII Redaction Enforcement
Given a redaction configuration that defines per-field actions (none|mask|remove) using schema registry PII tags When an audit pack is generated Then only fields marked pii:true in the active schema are redacted according to the selected action And non-PII fields remain unchanged And the chosen redaction is applied consistently across raw_logs.*, timelines, summaries, and anomalies And an automated scan using the schema registry PII tags finds zero unredacted PII values in the outputs
Asynchronous Job Lifecycle, Progress UI, Notifications, and Rate Limits
Given a user with permission initiates an audit pack generation When the job is created Then the UI shows status transitions (Queued, Running, Succeeded, Failed, Canceled) with percent progress (0–100%) and ETA updated at least every 5 seconds And the requester receives an in-app notification on start and on completion (success or failure), and an email notification if email alerts are enabled And the requester can cancel the job until it reaches Succeeded or Failed, and cancellation deletes partial artifacts and prevents share-link creation And transient storage or ledger read errors are retried up to 3 times with exponential backoff before the job fails with an error code and correlation ID And if the tenant or user rate limit is exceeded, the request is rejected with HTTP 429 and a Retry-After value, and no job is created
Export Packaging, Naming, Formats, and Schema Conformance
Given a successfully completed job When the ZIP is produced and stored Then the ZIP filename includes scope identifier, start/end timestamps, and job ID, and is stored in object storage under the tenant namespace And CSV files use UTF-8 encoding, a header row, comma delimiter, RFC 4180 quoting, and Unix line endings And JSONL files contain one valid JSON object per line with a trailing newline And all records in raw_logs.* validate against the active schema version retrieved from the schema registry at generation time And verification_instructions.txt specifies the schema version and object storage location used
Expiring Share Link Creation, Access Control, and Revocation
Given a successfully generated audit pack and a requested expiration timestamp within allowed policy When a share link is created Then the link is a signed, single-purpose URL bound to the exact object key and content hash And only authorized roles can create share links for the selected scope And link downloads are logged with requester identity, timestamp, IP, and user agent And the link returns HTTP 200 before expiry and HTTP 410 after expiry And an authorized user can revoke the link prior to expiry, after which it is immediately invalid
Export Action Logged in the Audit Ledger
Given an audit pack generation is requested When the export action is executed Then a ledger entry is written containing requester identity, timestamp, scope, time window, redaction configuration hash, job ID, pack object key, pack content hash, signature fingerprint, share link expiry (if created), and outcome (Succeeded|Failed|Canceled) And the ledger entry appears in ledger queries within 10 seconds of job completion And the generated audit pack’s raw logs include the export action entry when the time window encompasses the export timestamp
SIEM Streaming Connectors
"As a security engineer, I want to stream audit logs to our SIEM in real time so that our detection rules and dashboards stay current without manual exports."
Description

Provide real-time and batch streaming of audit events to external SIEMs and data lakes via Syslog TCP/TLS (CEF/LEEF), HTTPS webhooks (signed, retries with backoff and DLQ), AWS Kinesis/Firehose, Azure Event Hubs, and Google Pub/Sub. Support at-least-once delivery with per-tenant ordering, replay from cursor, backfill, throughput controls, and schema version tagging. Include a UI for configuring endpoints, secrets, test events, health checks, and delivery metrics/alerts. Map the unified schema to destination formats and maintain connector-specific transformations.

Acceptance Criteria
Syslog TCP/TLS Streaming in CEF/LEEF
Given a SIEM endpoint reachable via Syslog over TLS 1.2+ with a valid CA chain configured When a tenant enables Syslog TCP/TLS in CEF and streams 1,000 audit events over 5 minutes Then the connector establishes a TLS session and sends CEF-compliant messages including deviceVendor, deviceProduct, deviceVersion, signature, name, and severity And per-tenant event order is preserved end-to-end And ≥99.9% of events are delivered within 10 seconds end-to-end latency And no events are lost (duplicates allowed to satisfy at-least-once semantics)
HTTPS Webhook with Signature, Retries, and DLQ
Given a configured HTTPS webhook with a shared secret and 10s timeout When ClipSpark delivers events Then each request includes an HMAC-SHA256 signature header and signed timestamp, and the signature verifies against the payload And responses with 2xx are acknowledged with no retry When the endpoint returns 5xx or times out Then the connector retries with exponential backoff (1s, 2s, 4s, 8s, 16s, 32s) up to 6 attempts, preserving per-tenant ordering And after max retries, the event is written to a DLQ with last status, error, and retry count And 4xx responses are not retried and are written to the DLQ immediately And DLQ items can be re-enqueued manually with audit trail
Cloud Stream Connectors: Kinesis/Firehose, Event Hubs, Pub/Sub
Given valid cloud credentials and destinations exist (Kinesis stream or Firehose delivery stream, Azure Event Hub, Google Pub/Sub topic) When a tenant configures each connector via the UI and runs "Send Test Event" Then a synthetic audit event is successfully published to each destination and is observable via cloud-native metrics/logs within 60 seconds And delivery uses provider-recommended libraries with idempotency keys where available And per-tenant event ordering is preserved to a single partition/shard where supported And connection health reflects "Healthy" on success and surfaces actionable errors on failures (auth, permissions, not found)
Replay from Cursor and Backfill Range
Given an event cursor (eventId or RFC3339 timestamp) is selected for a tenant When the user initiates a replay from the cursor Then events at and after the cursor are retransmitted in original per-tenant order And events before the cursor are not retransmitted When the user requests a backfill for a time window Then only events within the window are sent, tagged with replay=true and original eventId for consumer deduplication And replay and backfill jobs expose progress (% complete), counts sent, duplicates detected, and completion status
Throughput Controls, Batching, and Backpressure
Given throughput limits are configured (max 2,000 events/sec per tenant, max batch size 500, max in-flight batches 10) When incoming event rate exceeds limits Then the connector applies batching and throttling to respect configured caps without process crashes or unbounded memory growth And upstream producers receive backpressure signals or queued status And persistent queue disk usage remains below 80% of allocated capacity with oldest-first spillover protection And upon recovery, delivery resumes without violating per-tenant ordering or at-least-once guarantees
Schema Version Tagging and Destination Mappings
Given the unified audit event schema with schemaVersion tag When events are emitted with versions v1 and v2 concurrently Then each connector includes schemaVersion in the payload/headers and maps fields to destination format (CEF/LEEF, JSON) per mapping spec And unknown fields are ignored without delivery failure, while missing required fields cause a clear, logged error and DLQ write And mapping unit tests cover 100% of required fields for each destination format And a feature flag allows rolling back to prior mappings without redeploy
UI Configuration, Secrets Handling, Health, Metrics, and Alerts
Given a tenant with Admin role When the admin creates or edits a connector in the UI Then endpoint URLs, credentials, and secrets are validated client- and server-side, stored encrypted at rest, and masked in the UI and logs And "Test Connection" sends a synthetic event and displays success/failure with reason within 15 seconds And the Health view shows status (Healthy/Degraded/Down), last delivery time, delivery latency p50/p95, error rate, backlog, and DLQ size per connector And alerts can be configured for error rate >1% over 5 minutes, latency p95 > 10s, backlog > 10,000 events, or DLQ growth > 100 events/hour, delivering notifications to Email and Slack And all admin actions are recorded in the Audit Ledger
Integrity Verification API and CLI
"As an auditor, I want to independently verify the audit ledger’s integrity so that I can trust the evidence provided during assessments."
Description

Expose authenticated API endpoints and a companion CLI to fetch and verify ledger integrity over a time range or event set. Return block digests, signatures, and checkpoint proofs; validate chain continuity and detect gaps or tampering. Support offline verification using published daily chain roots and provide a human-readable verification report. Include rate limiting, pagination, example scripts, and a chain-health status endpoint. Integrate with the audit pack generator to embed verification artifacts.

Acceptance Criteria
API: Fetch Ledger Segment by Time Range Returns Verifiable Artifacts, Pagination, and Rate Limiting
Given a valid OAuth2 Bearer token and an existing ledger with blocks in the inclusive range [from_ts, to_ts] When the client calls GET /v1/ledger/blocks?from_ts=YYYY-MM-DDTHH:MM:SSZ&to_ts=YYYY-MM-DDTHH:MM:SSZ&limit=100 with Authorization header Then the response status is 200 and Content-Type is application/json And the body contains blocks[] ordered ascending by index, each with fields: index (int), ts (RFC3339), digest (hex), prev_digest (hex), signature {alg, key_id, sig}, and checkpoint_proof present at checkpoint boundaries And for every i > 0 in the page, blocks[i].prev_digest equals blocks[i-1].digest And the body includes pagination {has_more (bool), next_cursor (string|null)}; calling the same endpoint with cursor=next_cursor returns the next non-overlapping page with no duplicate or missing indexes And the response includes rate limit headers X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset When the client exceeds the rate limit Then the response status is 429 with a Retry-After header and no blocks[] field is returned
CLI: Range Verification Detects Gaps and Tampering
Given CLIPSPARK_TOKEN is set and network access is available When the user runs: clipspark ledger verify --from 2025-01-01T00:00:00Z --to 2025-01-31T23:59:59Z Then the process exits with code 0 and stdout contains a summary including "Verified", "blocks:", "gaps: 0", "mismatches: 0", and "tampering: none" When the verification encounters a missing index or digest mismatch within the requested range Then the process exits with a non-zero code and stdout includes the first failing index and reason ("gap detected" or "digest mismatch"), and no success summary is printed
Offline Verification Using Published Daily Chain Roots
Given a local file daily_roots.json containing published checkpoint roots and a local blocks export file blocks_2025-01.json When the user runs: clipspark ledger verify --offline --roots daily_roots.json --input blocks_2025-01.json Then no network requests are made, daily checkpoints are verified against published roots, and the process exits with code 0 with a line containing "offline verification: passed" When any block-derived root does not match the corresponding published daily root Then the process exits with a non-zero code and stdout identifies the first failing checkpoint date and mismatch details
Human-Readable Verification Report Generation
Given the user runs: clipspark ledger verify --from 2025-01-01T00:00:00Z --to 2025-01-31T23:59:59Z --report report.txt Then report.txt is created in UTF-8, is human-readable, and contains sections: Range, Summary (total_blocks, gaps, mismatches), Signatures (alg, key_id), Checkpoints (dates and roots verified), and Artifact Hashes (SHA-256) And the report's final line starts with "Result: PASS" on success or "Result: FAIL" on failure And the command exits 0 on pass and non-zero on fail irrespective of report file creation
Chain-Health Status Endpoint Returns Accurate Snapshot
Given a valid Bearer token When the client calls GET /v1/ledger/health Then the response status is 200 and Content-Type is application/json And the body includes: status in ["green","amber","red"], last_block_index (int >= 0), last_block_ts (RFC3339), continuity_ok (bool), last_checkpoint_ts (RFC3339|null), chain_root (hex), service_time_ms (number) And continuity_ok=false implies status != "green" And last_block_ts >= last_checkpoint_ts when last_checkpoint_ts is present
Audit Pack Embeds Verification Artifacts
Given the user runs: clipspark audit-pack generate --from 2025-01-01T00:00:00Z --to 2025-01-31T23:59:59Z --include-verification Then a .zip file is produced containing at minimum: verification_report.txt, verification.json, checkpoint_roots.json, signatures.json, and manifest.json And verification.json includes fields: range, total_blocks, gaps, mismatches, first_failure (nullable), checkpoints_verified[], chain_root, generated_at (RFC3339) And the manifest contains SHA-256 hashes for each file and the hashes match the pack contents When clipspark audit-pack verify <pack.zip> is executed Then it exits 0 if all embedded artifacts are intact and consistent, otherwise non-zero with the first mismatch reported
Example Scripts Demonstrate API and Offline Verification Flows
Given the repository contains an examples/ directory with scripts When the user runs examples/verify_range.sh with CLIPSPARK_TOKEN and RANGE environment variables set Then the script exits with code 0, prints a PASS summary, and writes a report file under examples/output/ When the user runs examples/verify_offline.py with --roots daily_roots.json --input blocks.json Then it exits 0 on valid inputs and non-zero on mismatches, printing the first failure to stderr
Role-based Audit Access & Privacy Controls
"As a tenant admin, I want strict role-based controls and privacy safeguards on audit data so that we protect user privacy and comply with regulatory requirements."
Description

Implement fine-grained RBAC scopes for viewing, searching, and exporting audit data, with least-privilege defaults (Viewer, Investigator, Admin) and approval workflows for large exports. Enforce tenant isolation, regional data residency, legal hold, and retention policies. Provide configurable privacy controls (IP anonymization, identifier hashing, selective redaction) and log all audit-data access (“audit of the audit”). Expose settings via UI and API with clear defaults and guardrails.

Acceptance Criteria
Least-Privilege RBAC Defaults Applied
Given a new tenant with default RBAC settings When users with roles Viewer, Investigator, and Admin access audit data Then permissions are enforced as: - Viewer: can list and view audit entries within their tenant; cannot export; cannot modify settings; sees anonymized/redacted fields as configured - Investigator: can list, view, and search within their tenant; can export when estimated rows <= Large Export Threshold; cannot modify settings - Admin: can view, search, export; can modify all audit and privacy settings; can approve export requests Given the default Large Export Threshold is 10000 rows and no overrides exist When an Investigator attempts to export 12000 rows Then the export is blocked pending approval and no data is exported immediately Given a Viewer attempts any export When they initiate an export Then the API returns 403 Forbidden and the UI displays an authorization error
Approval Workflow for Large Exports
Given Large Export Threshold is configured to T rows And a user initiates an export estimated > T rows When the export request is submitted Then an approval request is created capturing requester, role, filters, estimated rows/size, and reason And notifications are sent to Admin approvers And the export cannot start until approved Given an Admin approves within 72 hours When approval is granted Then a single-use signed export link is generated And the link expires after 24 hours if unused And the actual exported row count is recorded And audit events are written for request, approval/denial, and fulfillment Given no Admin approves within 72 hours When the approval window elapses Then the request status becomes Expired and no data is exported Given an Admin denies the request When denial is submitted with a reason Then the requester is notified and no data is exported
Tenant Isolation and Regional Data Residency Enforcement
Given user U belongs to tenant A and residency is set to region R for tenant A When U queries or filters including identifiers belonging to tenant B Then the API returns 403 Forbidden and no cross-tenant data is returned And an access-attempt audit event is recorded Given tenant A residency region is EU When audit records are stored or exported Then data at rest resides in EU-designated storage And export download endpoints resolve to EU region And SIEM streaming endpoints for tenant A are EU-based Given cross-region replication is not explicitly enabled by Admins When residency settings are inspected Then no copies of audit data exist outside the configured region
Legal Hold and Retention Policy Compliance
Given a retention policy of R days and no legal hold When records exceed R days of age Then they are purged within 24 hours And a purge summary audit event is recorded with counts Given a legal hold is applied to scope S (tenant/date range/filter) When the purge job runs Then records matching S are not deleted regardless of age And delete actions on S are blocked unless policy explicitly allows export under hold Given a legal hold is removed When the next purge cycle runs Then previously held records older than R days are purged within 24 hours Given an Admin changes retention from R to R2 When the change is saved Then validation enforces R2 within 1..3650 days And the change is audited with old/new values
Privacy Controls: IP Anonymization, Identifier Hashing, Selective Redaction
Given IP anonymization is enabled When viewing, searching, exporting, or streaming audit data Then IPv4 addresses have the last octet zeroed (e.g., 192.168.1.123 -> 192.168.1.0) And IPv6 addresses have the last 80 bits zeroed And raw IPs are not exposed via UI, API, exports, or SIEM stream Given identifier hashing is enabled for fields [user_id, email] When those fields appear in audit data Then values are returned as deterministic salted SHA-256 hashes unique per tenant And the salt is not retrievable via UI or API And identical inputs hash to identical outputs within the tenant Given selective redaction is enabled for configured keys K When events contain keys in K Then values are replaced with "[REDACTED]" across UI, API, exports, and streams Given privacy controls are toggled in settings When preview is requested Then the UI shows a sample before/after transformation on representative events
Audit of the Audit (Access and Change Logging)
Given any user views, searches, exports, or changes settings related to audit data When the action is performed Then an immutable audit event is recorded containing actor ID, role, tenant, timestamp, action type, parameters (filters, fields, counts), client IP (subject to anonymization), and result (success/denied) Given audit events are chained cryptographically When a new event E_n is written Then it stores a prev_hash referencing E_(n-1) and a hash over its contents And the chain integrity endpoint returns Valid for the last N events when no tampering occurs Given any stored event is altered or removed outside normal flow When chain integrity is verified Then the endpoint returns Invalid and identifies the first broken link Given an export is executed When it completes Then an audit event records estimated vs actual rows, file checksum, and expiry time of the link
Settings via UI and API with Defaults and Guardrails
Given an Admin views Audit Settings in the UI or via API When configuration is retrieved Then defaults are present: Large Export Threshold=10000 rows, IP anonymization=On, Identifier hashing=On, Selective redaction configurable, Retention=365 days, Residency=tenant-assigned region Given an Admin updates settings with invalid values (e.g., threshold=0, retention_days=40000, region=unsupported) When the request is submitted Then the API returns 400 with field-specific error codes and messages And no changes are applied Given a non-Admin attempts to change settings via UI or API When the request is submitted Then the API returns 403 Forbidden and the UI displays an authorization error And no changes are applied Given valid changes are saved When confirmed Then changes propagate to enforcement within 60 seconds And a settings-change audit event is recorded with old/new values, actor, and reason (if provided) Given settings are retrieved via API by an authorized user When GET /audit/settings is called Then the response includes current values, default values, guardrail ranges, and effective policy source (default vs override)
Secure Time and Key Management
"As a security architect, I want robust time-stamping and managed signing keys for the ledger so that integrity proofs remain trustworthy over time and through incidents."
Description

Back ledger entries with trusted time and keys: synchronize time with authenticated NTP and drift monitoring; optionally anchor checkpoints to an RFC 3161 TSA or public blockchain at intervals. Store signing keys in HSM/KMS with rotation, revocation, and access auditing. Ensure cross-region replication, disaster recovery procedures, startup integrity checks, and continuous monitoring of time and key health. Document cryptographic parameters and rotation policies to maintain long-term verifiability of signatures and timestamps.

Acceptance Criteria
Authenticated NTP Synchronization and Drift Monitoring
Given the ledger service starts, When time synchronization initializes, Then it must use at least 3 authenticated NTP/NTS servers with a defined quorum and authenticated mode enabled And the selected time offset must be derived from a majority quorum with max peer variance <= 250 ms And the effective system offset must be <= 500 ms under normal operation Given ongoing operation, When time drift exceeds 500 ms for more than 60 seconds, Then a High severity alert is emitted to monitoring and SIEM within 60 seconds And time drift > 2 seconds causes the ledger to fail closed for new writes until offset returns <= 500 ms And all time sync events, offsets, selected peers, and auth status are recorded to the audit log
Checkpoint Anchoring via RFC 3161 TSA and Public Blockchain
Given anchoring is enabled with a 15–60 minute interval, When a checkpoint is created, Then an RFC 3161 timestamp token (TST) is generated over the checkpoint hash using the configured TSA And the TSA certificate chain and OCSP/CRL status are validated and stored with the checkpoint metadata And a public blockchain anchor is submitted embedding the checkpoint Merkle root, returning a transaction ID Given network or TSA failure, When anchoring attempts fail, Then retries follow exponential backoff up to 24 hours with no data loss And backlog anchors are caught up within 2 anchoring intervals after connectivity restoration Given an auditor requests proof, When verifying a checkpoint, Then the system exports an audit pack containing the checkpoint hash, TSA TST and chain, and blockchain TXID with inclusion proof, which verifies on an offline machine
HSM/KMS Key Storage, Rotation, and Revocation with Access Auditing
Given signing keys are created, When keys are provisioned, Then private keys must be created and remain non-exportable within a FIPS 140-2/3 validated HSM/KMS And key policies enforce least privilege and dual control for deletion Given steady-state, When rotation time reaches 90 days (configurable), Then a new signing key is generated, activated for new entries, and the prior key remains active for verification only And key IDs, creation times, and algorithms are embedded in ledger metadata for each entry Given a compromise is suspected, When a key is revoked, Then revocation is recorded with an effective time, CRL/OCSP (if applicable) is updated, alerts are sent within 60 seconds, and new writes with the revoked key are rejected And all key operations (create, rotate, sign, revoke, destroy) are auditable with actor, purpose, timestamp, and outcome, and streamed to SIEM within 60 seconds
Cross-Region Replication and Disaster Recovery
Given the service is healthy, When writes occur, Then ledger data and key materials (wrapped) are replicated to at least two secondary regions with replication lag <= 60 seconds Given a primary region outage, When failover is initiated, Then the system meets RTO <= 15 minutes and RPO <= 60 seconds And post-failover validation shows no hash-chain breaks and no missing signatures or timestamps Given quarterly DR exercises, When a simulated region failure is executed, Then recovery objectives are met and results are recorded in the audit log and DR report artifacts
Startup Integrity and Safe-Mode Enforcement
Given the service is starting, When initialization runs, Then it verifies continuity of the ledger hash chain and signatures for at least the last 10,000 entries (configurable) and the most recent 24 hours of checkpoints And verifies TSA anchors and blockchain anchors for the most recent checkpoint (if enabled) And validates time sync health (authenticated peers, offset <= 500 ms) Given any integrity or time check fails, When enabling write mode, Then the system fails closed (read-only), emits Critical alerts, provides explicit error codes, and records a self-test failure entry And successful startup records a signed self-test attestation entry with versions, key IDs, and crypto parameters
Continuous Monitoring, Thresholds, and Alerting
Given normal operation, When monitoring runs, Then metrics are collected for NTP offset, authenticated status, HSM/KMS health, key age to rotation, anchor backlog, replication lag, and audit log throughput And thresholds are enforced: NTP offset > 500 ms (warn), > 2 s (critical); replication lag > 60 s (critical); key age within 7 days of rotation (warn), past rotation (critical) And alerts are delivered to configured channels (email, webhook, PagerDuty, SIEM) within 60 seconds of threshold breach And a /healthz endpoint exposes red/yellow/green status with last-checked timestamps and reasons, without leaking secrets
Cryptographic Parameters and Long-Term Verifiability Documentation
Given a release is published, When documentation is generated, Then a versioned artifact describes algorithms (e.g., SHA-256, Ed25519 or ECDSA P-256), key sizes, TSA details, blockchain network, and rotation policies And each ledger entry includes key ID and algorithm metadata enabling independent verification Given an auditor downloads an audit pack, When executing provided verification scripts in a clean environment, Then signatures, hash-chain continuity, and timestamps verify without network access beyond TSA chain/CRL included in the pack And when algorithms are retired, Then prior entries remain verifiable using preserved, signed toolchain containers and documented procedures

Delegated Approvals

Introduce scoped admin tiers and time-bound exception workflows. Route requests (e.g., export override, retention pause) to the right approvers with auto-expiry and full traceability—keeping teams moving fast under strong guardrails.

Requirements

Scoped Admin Roles
"As a compliance lead, I want to assign scoped approvers to specific workspaces and exception types so that we can delegate decisions without exposing full admin privileges."
Description

Introduce role hierarchy with workspace-, project-, and content-level scopes to delegate approval authority without granting full admin rights. Roles include Global Admin, Compliance Admin, Workspace Admin, Approver, and Requestor with granular permissions for exception types (e.g., export override, retention pause). Integrates with ClipSpark teams and folders, respects existing access controls, and supports mapping to SSO/SCIM groups. Provides UI and API to assign roles per scope, with guardrails to prevent self-approval where conflicts exist.

Acceptance Criteria
UI: Assign Workspace Admin Role at Workspace Scope
Given a Global Admin is viewing Workspace "Acme West" access settings And user "Pat Lee" is an active ClipSpark member When the admin assigns the role "Workspace Admin" scoped to Workspace "Acme West" via the UI and confirms Then "Pat Lee" can perform admin actions only within Workspace "Acme West" (create/delete projects, manage approvers) And "Pat Lee" cannot perform admin actions in any other workspace And the assignment appears in the Roles table showing role "Workspace Admin" and scope "Workspace: Acme West" And an audit log entry is created capturing actor, assignee, role, scope, and timestamp
API: Assign Approver Role at Project Scope
Given a Global Admin has a valid API token with role-assignment permissions When they call POST /roles/assign with payload { userId, role: "Approver", scopeType: "Project", scopeId: "BIO-101" } Then the API responds 201 Created with the created assignment including role and scope And the user gains Approver permissions only for Project "BIO-101" And attempting to assign with an invalid scopeId responds 404 Not Found And attempting to assign without required permission responds 403 Forbidden And an audit log entry is recorded with requestId, actorId, userId, role, scopeType, scopeId
Granular Exception Permissions: Export Override Only
Given user "Jordan Kim" has role Approver at Project "BIO-101" with exception permissions limited to ["export_override"] When a Requestor submits an export override request for a video within Project "BIO-101" Then Jordan can view, approve, or deny that request And approval/denial creates an audit entry with requestId, decision, actorId, scope When a Requestor submits a retention pause request within Project "BIO-101" Then Jordan cannot approve or deny; the UI action is disabled and any API attempt returns 403 with code "INSUFFICIENT_PERMISSION"
Prevent Self-Approval and Conflicts of Interest
Given user "Avery Shaw" is the Requestor of an export override on Content "VID-7788" within Project "BIO-101" And Avery also holds Approver role for export overrides in the same project When Avery attempts to approve their own request via UI or API Then the system blocks the action and displays "Self-approval is not permitted" And the request is automatically routed to the next eligible Approver in the same scope (or escalated to Compliance Admin if none exist) And an audit log entry records the blocked attempt with reason "conflict_of_interest" And no approval state change occurs on the request
Respect Existing Access Controls During Approval
Given user "Casey Wu" is an Approver for Workspace "Acme West" And Casey does not have view access to Folder "Legal/Privileged" (content-level ACL denies access) When Casey opens an approval request for content in Folder "Legal/Privileged" Then the system hides the content body and shows only minimal metadata (title, request type, requester, timestamps) And the approve/deny actions are disabled with message "Access required to act on this content" And any API attempt to approve returns 403 with code "CONTENT_ACCESS_REQUIRED"
SSO/SCIM Group-to-Role Mapping Sync
Given SCIM group "Compliance-Team" is mapped to role "Compliance Admin" scoped to Workspace "Acme West" When a new user is added to "Compliance-Team" in the IdP Then within 5 minutes the user is granted "Compliance Admin" for Workspace "Acme West" And when a user is removed from "Compliance-Team" Then within 5 minutes the mapped role is revoked for that user And manual role assignments outside this mapping remain unchanged And each grant/revoke from SCIM sync is recorded in the audit log with source "SCIM"
Time-Bound Delegation Rules
"As a team admin, I want to delegate approval rights to a colleague during my vacation window so that requests continue to move without breaking policy."
Description

Enable administrators to create delegation rules that grant temporary approval authority for defined time windows and scopes (user/group, workspace, exception type). Rules support start/end timestamps, timezone handling, and automatic deactivation upon expiry. Includes safeguards for overlapping rules, blackouts, and conflict resolution. Works alongside baseline roles to allow out-of-office coverage and audit-friendly exceptions.

Acceptance Criteria
Create Time-Bound Delegation With Timezone
Given I am an Org Admin with permission to manage delegations When I create a delegation rule with: - delegate=User D, approver=User A, target=Group G in Workspace W, exceptionType=ExportOverride - start=2025-11-03T09:00 America/Los_Angeles, end=2025-11-10T18:00 America/Los_Angeles Then the system validates start < end and both timestamps are provided And the timezone is a valid IANA identifier And the system stores start/end in UTC and preserves the timezone identifier And the rule is retrievable via API and UI with semantically equivalent localized times and exact scope And the API responds 201 Created with ruleId
Auto-Activation and Auto-Expiry of Delegation
Given a saved delegation rule with start S and end E When current time < S (by the rule's timezone) Then the delegate cannot approve within the rule's scope When current time enters [S, E) Then the delegate can approve within the rule's scope within 60 seconds of S When current time >= E Then approvals by the delegate in the rule's scope are blocked within 60 seconds of E and the rule shows status=Expired And after a service restart, active/expired state is recomputed without manual action
Scope Enforcement: User/Group, Workspace, Exception Type
Given a delegation scoped to delegate=User D for exceptionType=RetentionPause targeting Group G within Workspace W When User D attempts to approve a RetentionPause for a member of Group G in Workspace W during the active window Then the approval is permitted When User D attempts to approve for a different exception type or for a target outside Group G or outside Workspace W Then the approval is denied with error=scope_mismatch and the attempt is audit-logged
Overlapping Delegations and Conflict Resolution
Given multiple delegation rules overlap in time and scope for the same delegate/targets When one or more rules deny (e.g., via blackout) and others allow Then deny takes precedence and the approval is blocked with error=denied_by_higher_precedence When multiple allow rules apply with differing specificity Then the most specific scope wins: user > group > workspace, and the decision records winningRuleId and precedence And the effective allowed window equals the union of allow windows minus any deny windows
Blackout Window Enforcement
Given an organization-level blackout window for exceptionType=ExportOverride from Bstart to Bend When an admin attempts to create a delegation whose active window overlaps [Bstart, Bend] Then the system blocks creation with validation error=blackout_overlap and no rule is saved When an existing delegation's active window intersects a blackout Then during [Bstart, Bend] approvals by the delegate are blocked with error=blackout_active and UI indicates temporary block And all blocked attempts are audit-logged with blackoutId and ruleId
Baseline Role Coexistence and Out-of-Office Coverage
Given baseline roles are always in effect When a delegate already has baseline approval for the same exception type and scope Then the delegation does not expand scope but activation/expiry events are still recorded When a delegate lacks baseline approval Then during the active window they can approve only within the delegated scope and no broader permissions are granted And upon expiry the delegate immediately reverts to baseline capabilities
Audit Logging and Traceability for Delegations
Given audit logging is enabled by default When a delegation is created, updated, activated, auto-expired, or deleted Then an immutable audit event is recorded with timestamp (UTC), actor, action, ruleId, scope, and before/after values When an approval decision is permitted or denied due to delegation or blackout Then the decision record includes governing ruleId(s)/blackoutId, reason, and requestId and is searchable via filters And admins can export audit logs by date range, actor, ruleId, blackoutId, and outcome with consistent CSV/JSON schemas
Policy-Based Exception Types
"As a security admin, I want to define standardized exception types with required justifications and durations so that approvals are consistent and compliant."
Description

Provide configurable catalog of exception request types (e.g., export override, retention pause, external share) with per-type form fields, validation, required attachments, maximum duration, and default approver policies. Allows product admins to define SLAs, auto-expiry behavior, and whether multi-step approvals are required. Exception definitions are versioned and can be toggled per workspace.

Acceptance Criteria
Admin Creates New Exception Type with Custom Fields
Given a Product Admin in Workspace A, When they create a new Exception Type named "Export Override" with fields: Reason (text, required, max 500 chars), Record IDs (list, required, max 100 items), Justification (enum: Legal, Compliance, Customer Request), and Required Attachments = true, Then the type is saved with a unique identifier, enabled in Workspace A, and appears in the exception type catalog within 5 seconds. And the stored schema is retrievable via the admin API and matches the configured fields and constraints exactly. And an audit log entry records the actor, workspace, field schema, constraints, and timestamp.
Enforce Required Attachments and Field Validation
Given the "Export Override" type requires at least 1 attachment of types [pdf, docx, txt] with max size 10 MB each, When a requester submits with zero attachments, Then submission is blocked with an inline error "Attachment required" and no request is created. When Reason length exceeds 500 characters, Then submission is blocked with an inline error indicating the limit. When Justification is not one of [Legal, Compliance, Customer Request], Then submission is blocked with an inline error for invalid value. When all fields pass validation and at least one valid attachment is included, Then submission succeeds and a request ID is returned within 2 seconds.
Maximum Duration and Auto-Expiry Enforcement
Given Max Duration = 14 days and Auto-Expiry = enabled for the type, When a requester enters a duration of 30 days, Then the form shows a blocking error "Duration exceeds maximum (14 days)". When a request is approved for 7 days at 2025-09-14 10:00 UTC, Then the system sets expiry at 2025-09-21 10:00 UTC and schedules revocation. And 24 hours before expiry, notifications are sent to the requester and current approver(s). And at expiry, temporary access is revoked, the request status changes to "Expired" within 2 minutes, and an audit event is recorded.
Default Approver Policy Routing and SLA Tracking
Given Default Approver Policy = Data Steward Group and SLAs: first-response = 12 business hours, decision = 48 business hours, When a request is submitted, Then it appears in the Data Steward Group queue within 30 seconds and the SLA timer starts. If no action is recorded within 12 business hours, Then SLA status becomes "Breached: First Response" and an escalation notification is sent to the Data Steward Manager. If a final decision is recorded within 48 business hours, Then SLA status is "Pass"; otherwise it becomes "Breached: Decision" and escalates per policy. SLA timestamps (start, first response, decision) and current SLA status are visible on the request details and exportable via API.
Multi-Step Sequential Approval Workflow
Given the type is configured with Step 1 = Data Steward approval (any member) and Step 2 = Legal approval (role-based), both required, When a request is submitted, Then Step 1 must be approved before Step 2 becomes actionable. If Step 1 is rejected, Then the request closes with status "Rejected" and Step 2 never opens. Approvals and rejections require a non-empty comment; empty comments are blocked with validation. Each step logs approver identity, decision, comment, and timestamp; the audit trail shows steps in chronological order. If Step 1 is not completed within its 24-hour step SLA, Then it auto-escalates to the Data Steward Manager and the escalation is logged.
Versioning and Workspace Toggle Behavior
Given Exception Type "Export Override" v1 is active in Workspace A and disabled in Workspace B, When v2 is created with updated field constraints and published, Then new requests in Workspace A use v2 while existing v1 requests retain v1 schema and rules. When v1 is marked Deprecated, Then it cannot be used for new requests but existing v1 requests continue unaffected. When the type is toggled OFF in Workspace A, Then it is hidden from requesters in that workspace within 30 seconds and new submissions are blocked; active requests continue unaffected. All publishes, deprecations, and toggles create immutable audit entries including actor, from->to state, version number, affected workspaces, and timestamp.
Dynamic Approval Routing
"As a requester, I want my exception routed automatically to the right approvers based on policy so that I don’t have to chase people or guess the process."
Description

Route incoming requests to the correct approvers based on policy, scope, data sensitivity, and requester affiliation. Supports single- or multi-step flows (e.g., content owner -> workspace approver -> compliance), parallel or sequential steps, and fallback to delegate lists. Includes routing rules using attributes like video classification, export destination, and retention age. Offers API/webhooks for external workflow tools and records all routing decisions.

Acceptance Criteria
Attribute-Based Routing to Correct Approver Tier
Given routing rules map combinations of video classification, export destination, retention age, and requester affiliation to approver groups And a rule exists: classification=Sensitive AND export_destination=External AND retention_age>=365 AND requester_affiliation=Contractor -> approver_groups=[workspace_owners_{ws_id}, compliance_admin_{region}] When a requester submits an export override for a video matching those attributes in workspace WS123 (region=US) Then the system evaluates rules in documented priority order and selects approver_groups exactly ["workspace_owners_WS123","compliance_admin_US"] And no additional approver groups are included and duplicates are removed And the evaluation completes within 500ms at p95 and 1s at p99 And the computed route (route_version, approver_group_ids, priority_rule_ids) is persisted with a routing_decision_id and retrievable via API for the request
Sequential Multi-Step Approval Flow (Owner -> Workspace -> Compliance)
Given policy "retention pause" is configured with sequential steps: Step1=Content Owner, Step2=Workspace Approver, Step3=Compliance When a request R456 is created for a video whose owner is U1 in workspace WS123 Then only Step1 approvers are notified and able to act; Step2 and Step3 remain locked And upon an approval by any eligible Step1 approver, Step2 activates within 5 seconds and notifies its approvers; Step3 remains locked And upon an approval by any eligible Step2 approver, Step3 activates within 5 seconds And if any step is Rejected, the request state becomes Rejected and no subsequent steps activate And the request state becomes Approved only after all steps are approved, with per-step and final timestamps recorded
Parallel Approvals with All-Must-Approve Aggregation
Given the policy for "export override" contains a parallel step with approver_sets=[Security, Compliance] and aggregation=ALL When a request R789 is created Then both Security and Compliance approver sets are notified concurrently within 10 seconds And the step state becomes Approved only when both approver sets record an Approval And if any approver in either set records a Rejection, the parallel step becomes Rejected and the overall request becomes Rejected And partial approvals display as Pending with per-set status until all required sets approve And SLA for the parallel step is 48 hours; upon SLA breach the system triggers escalation rules (without bypassing scope) and records the escalation event
Delegate Fallback and SLA-Based Escalation
Given each approver set may have a prioritized delegate list and approvers can be marked Out-Of-Office (OOO) When an active step has no eligible primary approver (empty group or all OOO) OR no primary approver responds within the configured SLA (e.g., 24 hours) Then the system routes to and notifies delegates in priority order within 60 seconds of detection And delegated approvers inherit the same scope constraints as the primary approver set And if no delegates are available, the system escalates to the next scoped admin tier defined by policy (not to global admins) and records the escalation And the audit record includes fallback_reason, detection_timestamp, chosen_delegate_ids or escalated_tier_id
Time-Bound Exception Routing with Auto-Expiry
Given a time-bound exception E1 is configured: for program=PX, request_type="export override", route to Program Admins between 2025-10-01T00:00Z and 2025-10-07T23:59Z, auto_expire=true When a matching request is created inside the window Then routing uses Program Admins instead of the default path and records exception_id=E1 in the routing decision When a matching request is created after the window Then the routing reverts to the default path; E1 is not applied And in-flight requests created during the window continue with the exception route and are not re-routed solely due to expiry And all applications of E1 (with timestamps) are captured in the audit trail; the exception automatically deactivates without manual action at expiry
Webhook Event Delivery for External Workflow Tools
Given a webhook endpoint is configured with a shared secret and retry policy (max_attempts=3, exponential backoff starting at 5s) When a routing decision is created or updated for a request Then the system POSTs a JSON payload including request_id, routing_decision_id, event_type, matched_rule_ids, approver_sets, step_type, and an HMAC-SHA256 signature header within 2s p95 and 5s p99 And failed deliveries are retried per policy with an Idempotency-Key header to support receiver deduplication And after 24 hours without success, delivery status is marked Failed and is visible via API with last_error and attempt_count And payloads exclude PII beyond hashed user identifiers per policy
Audit Trail of Routing Decisions
Given auditing is enabled by default for routing operations When any routing decision is computed or changed Then the system persists an immutable entry containing: request_id, video_id, workspace_id, input attributes (classification, export_destination, retention_age, requester_affiliation), evaluated rule_ids with outcomes, selected approver_sets with user_ids, timestamps, actor/system, reason codes, and versioned policy identifiers And audit entries are append-only with tamper-evident hash chaining and cannot be altered by administrators And entries are queryable via API by request_id, date_range, rule_id, approver_id, and exportable as CSV and JSON And given the recorded inputs and policy versions, a replay endpoint recomputes the route deterministically and matches the stored decision 100% of the time
Auto-Expiry, Escalation & Reversion
"As a compliance admin, I want exceptions to auto-expire and revert changes when their window ends so that we maintain guardrails without manual cleanup."
Description

Automatically expire pending requests and approved exceptions at configured deadlines, notifying stakeholders and reverting system state (e.g., resume retention, revoke export access). Provides escalation paths when SLAs are breached (e.g., escalate to compliance after 48 hours) and supports snooze/extend with justification. All expirations and reversions are logged with timestamps.

Acceptance Criteria
Auto-Expire Pending Requests at Deadline
Given a pending approval request with an expiry timestamp T and current time >= T When the expiry scheduler runs Then the request status changes to "Expired" And all stakeholders (requester, assigned approvers, watchers) are notified within 60 seconds And an audit log entry is created with action="request.expired" including requestId, previousStatus, expiredAt (UTC ISO 8601), and actor="system" And no further approval actions are permitted on the expired request
Auto-Revert Approved Exceptions on Expiry
Given an approved exception with a configured effect (e.g., ExportOverride, RetentionPause) and expiry timestamp T When current time >= T Then the system reverts the effect within 60 seconds (e.g., revoke export access, resume retention) And the exception record status becomes "Ended" And all stakeholders are notified of the reversion And an audit log entry is created with action="exception.reverted" capturing requestId/exceptionId, target resources/users, before/after states, revertedAt (UTC ISO 8601), and actor="system"
SLA-Based Escalation After Inaction
Given a pending request assigned to approver group X with an SLA of 48 hours from creation time C When current time >= C + 48 hours and the request is still in status "Pending" Then the request is escalated to the configured escalation group (e.g., Compliance) And the escalation group receives notification within 60 seconds And the request displays an escalation badge and logs the escalation level And an audit log entry is created with action="request.escalated" including reason="SLA_BREACH", previousAssignee, newAssignee, escalatedAt (UTC ISO 8601) And the system prevents duplicate escalations for the same SLA window
Snooze/Extend Exception with Justification and Policy Limits
Given a user with permission "Extend Exception" and an active exception with expiry T1 When the user submits an extension to new expiry T2 with justification text length >= 10 and (T2 - now) <= tenant policy maxExtensionWindow Then the exception expiry is updated to T2 And stakeholders are notified of the new expiry And an audit log entry is created with action="exception.extended" capturing oldExpiry, newExpiry, justification, extendedBy, extendedAt (UTC ISO 8601) And if justification is missing/too short or T2 exceeds policy, the extension is rejected with validation errors and no state change occurs
Resilient Reversion with Retry and Idempotency
Given an exception scheduled to revert at time T When the initial reversion attempt fails due to a transient error Then the system retries up to 5 times over 15 minutes with exponential backoff And upon final failure, the exception is marked "Reversion Failed" and on-call and compliance are alerted And each attempt is logged with action="exception.revert_attempt" including attemptNumber, outcome, error (if any), and timestamp (UTC ISO 8601) And reversion operations are idempotent: repeated executions do not duplicate revocations or notifications
Timezone-Aware Deadlines and UTC Logging
Given the tenant timezone is configured and the system clock is UTC When a request with SLA duration D or an exception with expiry at local time TL is created Then deadlines are computed using the tenant timezone, respecting DST transitions And all persisted timestamps in logs/events are recorded in UTC ISO 8601 with a trailing Z And API responses return both UTC timestamps and the tenant-localized deadline for clarity
Snooze Pending Request SLA with Justification
Given a user with permission "Snooze Request" and a pending request with SLA deadline D1 When the user snoozes by S hours (S <= tenant policy maxSnoozeHours) with justification text length >= 10 before D1 Then the SLA deadline updates to D2 = D1 + S and any scheduled escalation is rescheduled to D2 And stakeholders receive notification of the new deadline within 60 seconds And an audit log entry is created with action="request.snoozed" capturing oldDeadline, newDeadline, S, justification, snoozedBy, and snoozedAt (UTC ISO 8601) And if S exceeds policy or justification is missing/too short, the snooze is rejected with validation errors
End-to-End Audit Trail & Export
"As an auditor, I want a complete, exportable timeline of each approval and its effects so that I can verify compliance and trace accountability."
Description

Maintain immutable, timestamped records for every request, decision, escalation, delegation rule change, and resulting system action. Expose search and filters by user, content item, workspace, exception type, and date. Provide export to CSV/JSON and SIEM-friendly webhook for compliance reviews. Surface evidence links (e.g., policy version used, routing rationale) to support audits.

Acceptance Criteria
Immutable Audit Log for Approval Lifecycle
Given a user submits an exception request (e.g., export override) with a rationale When the request is created, evaluated, escalated, delegated, approved or denied, expires, or triggers a system action Then the system appends an audit event for each step with fields: event_id (UUIDv4), request_id, event_type, actor_id, actor_role, workspace_id, content_ids[], exception_type, timestamp (UTC ISO-8601 Z), rationale, decision, previous_status, new_status, evidence_links[], event_hash, prev_event_hash And audit events are immutable (updates/deletes return 403 and original record remains unchanged) And the hash chain validates per request_id (first prev_event_hash is null; each subsequent prev_event_hash equals the previous event_hash) And timestamps are monotonic per request_id and within 200 ms of server NTP time And events are queryable via UI/API within 5 seconds of write success
Audit Search and Filter Across Dimensions
Given at least 50,000 audit events exist across multiple workspaces When a reviewer filters by user_id, content_id, workspace_id, exception_type, and date range and optionally applies free-text search on rationale Then results include only matching events using AND semantics across filters and are sorted by timestamp (desc) by default And pagination supports limit/offset with default limit 50 and max 500; requesting beyond bounds returns empty set And query performance meets p50 <= 1.5s and p95 <= 3s for 50k events And invalid filters (e.g., malformed date) return 400 with actionable error details; no matches returns 200 with an empty list
Evidence Links and Routing Rationale Traceability
Given an approver records a decision on a request When the decision is submitted Then the audit event contains evidence_links including: policy_version_id, policy_url, routing_rule_id, rule_snapshot_checksum, and routing_simulation_id And each evidence link resolves with HTTP 200 and returns a read-only snapshot matching the checksum And updating the live policy or routing rules after the decision does not change the snapshot referenced by the event And if required evidence is missing or unreachable, the decision cannot be committed and returns 422 with details
Filtered Export to CSV and JSON
Given a reviewer has applied specific filters to the audit log When they request an export in CSV or JSON format Then the exported data contains exactly the filtered rows and columns in the documented schema and preserves sort order And CSV is UTF-8, RFC 4180 compliant with a header row; fields containing commas/newlines/quotes are properly quoted; line endings CRLF And JSON export is an array of objects; NDJSON is available when requested via format=ndjson And timestamps are ISO-8601 Z; booleans are true/false; nulls are explicit; arrays maintain order And large exports are chunked into files <= 100 MB each with a manifest and SHA-256 checksums; filenames include export_type, date, and filter_hash And exports up to 100,000 events complete within 2 minutes; progress and completion status are visible; failures show a retriable error message
SIEM Webhook Delivery and Retry
Given a SIEM webhook destination is configured with a shared secret When a new audit event is written Then the system POSTs the event within 5 seconds to the endpoint over TLS 1.2+ with a JSON body (including id, type, timestamp, request_id, workspace_id, actor, attributes) and headers X-Signature (HMAC-SHA256) and Idempotency-Key And 2xx responses mark the delivery successful; 4xx (except 429) do not retry; 5xx/network errors retry with exponential backoff and jitter for up to 24 hours; 429 respects Retry-After And deliveries preserve in-order sequence per request_id and are idempotent at the receiver via Idempotency-Key And failures after retry exhaustion are placed in a dead-letter queue; admins can view and replay DLQ items; alerts are emitted on DLQ insertion And webhook secret rotation supports dual-secret overlap without downtime
Role-Based Access and Redaction for Audit Views and Exports
Given role-based access controls are enabled (Owner, Compliance Admin, Workspace Admin, User) When a user attempts to view or export audit data Then only authorized roles can access audit events and only for workspaces they are permitted to view; others receive 403 without leaking record existence And PII fields (e.g., user email) are masked by default in UI and exports; Compliance Admins can reveal PII for a session after providing a justification, which is itself logged And export download links are single-use, expire after 15 minutes, and require authentication; all export downloads are logged And API access requires OAuth scope audit:read for views and audit:export for exports
Auto-Expiry of Exceptions Recorded with Outcomes
Given a time-bound exception was approved with an explicit expiry When the expiry time is reached Then the system automatically revokes the exception and logs an exception_expired audit event with fields: request_id, expired_at, enforcement_action, result_status, error(if any) And any downstream enforcement action (e.g., re-enable retention) is executed and logged with a linked event_id And a SIEM webhook is emitted for both the expiry and enforcement events; failures follow retry/DLQ rules And expired exceptions cannot be used to bypass policies; attempts are blocked and logged
Approval Inbox & Omnichannel Notifications
"As an approver, I want clear notifications and a focused inbox with context so that I can make fast, informed decisions without opening the full video each time."
Description

Deliver a centralized approval inbox in ClipSpark with batched actions, quick approve/deny, required-comment prompts, and context previews (key timestamps, summary). Send actionable notifications via email, in-app, and Slack/Teams with deep links and one-click decisions where policy allows. Respect quiet hours and notification preferences; ensure idempotency and secure links.

Acceptance Criteria
Centralized Approval Inbox Shows Context Previews
Given I am an authenticated approver with at least one pending request assigned to me When I open the Approval Inbox Then I see only requests assigned to me or my scoped admin role, sorted by newest first And each item displays request type, requester, policy name, submitted time, due or expiry time, and current status And each item includes a context preview with at least 2 key timestamps (clickable) and a 2–3 sentence summary And clicking a preview timestamp opens the source video at that timestamp with the request context highlighted And expired requests are labeled as expired and cannot be actioned And I can filter by request type and status and search by requester name or request ID
Quick Approve or Deny with Required Comment Enforcement
Given policy requires a comment on Deny and may require a comment on Approve for certain request types And I have a pending request visible in my inbox When I click Deny without entering a comment Then I am blocked from submitting and shown a required comment prompt with a minimum of 10 characters And when I enter a valid comment and confirm, the request is denied and removed from the pending list And an audit record is written with request ID, decision, comment, approver ID, timestamp, and channel=inbox And if the policy requires a reason code, I must select one before submission
Batched Actions on Multiple Requests
Given I select multiple pending requests that allow the same action When I choose Approve Selected or Deny Selected Then I am prompted once for any required global inputs, which are applied to all items that require them And the system processes up to 50 items per batch, displaying per-item success or failure And items that fail do not block others; I can retry failed items individually And an audit record is created per item with a shared batch identifier for traceability And items whose policy forbids batch action are excluded with a clear message before submission
Omnichannel Notifications with Deep Links and One-Click Actions
Given my notification preferences enable email, in-app, and Slack or Teams When a new approval request is assigned to me Then I receive a notification in each enabled channel within 60 seconds, subject to quiet hours And each notification includes request summary, due or expiry, and a deep link to the request And where policy allows one-click actions, the notification presents Approve and Deny actions inline And when I take action in any channel, the request status updates and other channel notifications reflect the resolved state
Idempotent and Secure Deep Links for Decisions
Given a notification contains an action link or button When the link is used the first time within its validity window Then the action is executed once and the user sees a success confirmation And subsequent uses of the same link are rejected as already processed and do not create duplicate actions And action links are signed and expire in 24 hours; after expiry, the user is redirected to authenticate and complete the action in-app And one-click actions are only honored if the policy allows them; otherwise the user is routed to the full approval form enforcing required steps
Quiet Hours, Preferences, and Digest Behavior
Given my profile has quiet hours and per-channel notification preferences configured When requests are assigned during quiet hours Then email and in-app notifications are queued until quiet hours end, unless marked urgent by policy And Slack or Teams notifications can be batched into a single digest at the configured digest time with up to 20 items And I can disable notifications per channel and disabled channels receive none And queued notifications are deduplicated so I do not receive more than one notification per request per channel

Brand Skins

Apply one-click brand templates to every Clip Card. Auto-embed logos, colors, fonts, and safe areas across aspect ratios (16:9, 9:16, 1:1) with per-channel presets for YouTube, LinkedIn, LMS, and more—ensuring on-brand, polished cards in seconds without manual design work.

Requirements

Brand Skin Builder
"As a marketing manager, I want to create reusable brand skins with our logo, colors, fonts, and safe areas so that all Clip Cards stay on-brand without manual design work."
Description

Provide an authoring interface to create reusable brand templates (skins) that define logos, color palettes, typography, and safe areas. Support uploading SVG/PNG logos, extracting brand colors, selecting/uploading licensed fonts with fallback stacks, and defining typography hierarchy (titles, captions, CTAs). Allow per-aspect-ratio layout variants (16:9, 9:16, 1:1) with layer-based positioning, margins, opacity, and watermark/disclaimer components. Store skins in an organization library with metadata and validation rules, ensuring consistent application across Clip Cards and exports.

Acceptance Criteria
Upload Logo and Extract Brand Colors
Given I am in the Brand Skin Builder When I upload an SVG or PNG logo file ≤ 10 MB and maximum dimension ≤ 8192 px Then the logo renders in the preview with transparency preserved And the file is saved to the skin without data loss Given a valid logo is uploaded When I trigger color extraction Then at least 3 and up to 6 dominant brand colors are detected and listed with hex values And duplicate or near-duplicate colors (ΔE < 2) are de-duplicated And each color swatch is editable (add/remove/reorder/rename) and persists on save Given an invalid or oversize file is uploaded When validation runs Then a descriptive error is shown and the previous state remains unchanged
Configure Typography Hierarchy with Licensed Fonts and Fallbacks
Given I upload OTF/TTF/WOFF/WOFF2 font files and confirm a license checkbox When the font passes validation (supported type, readable, basic Latin glyph coverage ≥ 80%) Then the font becomes selectable for Title, Caption, and CTA roles And I can set font size, weight, line-height, letter-spacing, and color per role with live preview And a required fallback stack (e.g., Inter, Helvetica, Arial, sans-serif) is stored Given the custom font fails to load in preview or export When rendering occurs Then the configured fallback stack is used without text overflow beyond safe areas Given an unsupported or unlicensed font is uploaded When validation runs Then the upload is blocked with an error and no changes are saved
Define Safe Areas per Aspect Ratio (16:9, 9:16, 1:1)
Given I select an aspect ratio variant When I set safe area insets as percentages for top/right/bottom/left Then the preview overlays a guide and constrains text layers to remain within the safe area And values persist per aspect ratio and are saved with the skin And safe area snapping occurs in 1% increments with keyboard nudging Given I attempt to place a layer outside the safe area When validation runs Then a non-blocking warning highlights the violation and lists offending layers
Create Layout Variants with Layer-Based Positioning and Properties
Given a skin includes variants for 16:9, 9:16, and 1:1 When I position logo, title, caption, CTA, watermark, and disclaimer layers Then each layer supports x/y position (percent), anchor alignment, margins (px), opacity (0–100%), and z-index ordering And lock/visibility toggles are available per layer and persist per variant And switching aspect ratios preserves independent positions per variant And undo/redo (≥ 20 steps) works for layer changes Given organization policy requires specific layers When I click Save Then validation blocks save until required layers are present and positioned
Configure Watermark and Disclaimer Components
Given I add a watermark layer When I choose placement (tile/center/corner) and set opacity between 5% and 60% Then the watermark renders behind text layers and within canvas bounds in preview And exports include the watermark at the specified opacity and position Given I add a disclaimer component When I enter up to 280 characters and enable auto-wrap with a background box Then the text remains within safe areas and maintains WCAG contrast ≥ 4.5:1 via auto-adjust or warning
Save Skin to Organization Library with Metadata, Validation, and Versioning
Given required fields are complete (name, ≥ 1 logo or color palette, typography for Title/Caption/CTA, and all three aspect ratio variants) When I click Save Then the skin is validated and saved with metadata (name, description, tags, owner, created/updated timestamps, version 1.0, status Active) And a unique identifier/slug is generated And the skin is searchable by name/tag and filterable by status And access is restricted to org members with Editor+ role; Viewers cannot edit And edits create a new immutable version (semantic version increment) with change notes
Apply Skin to Clip Card and Export Consistency across Channels
Given a saved skin is set as default for YouTube, LinkedIn, and LMS presets When I apply the skin to a Clip Card and generate 16:9, 9:16, and 1:1 previews and exports Then logos, colors, typography, safe areas, and layers match the Skin Builder preview for each aspect ratio And channel-specific overrides (e.g., CTA text) are applied where configured And exported MP4 and PNG thumbnails match preview positions within 1 px and color hex values exactly And if a custom font is unavailable, the fallback is used with layout shift ≤ 2% of canvas dimensions
Per-Channel Presets & Safe Zones
"As a content operations lead, I want channel-specific presets that respect each platform’s safe zones so that clips render correctly and look polished everywhere."
Description

Enable channel-specific presets (YouTube, LinkedIn, LMS, TikTok, etc.) that bind a skin to platform-safe areas, default aspect ratios, and export specs. Configure text/overlay safe zones, end-screen considerations, watermark intensity, CTA styles, and caption placement rules per channel. Auto-select the appropriate preset based on the chosen destination or export profile, preventing cropping, truncation, and platform non-compliance.

Acceptance Criteria
Auto-Select Channel Preset on Destination Choice
Given a user selects "YouTube" as the export destination for a new Clip Card When the Brand Skin panel is opened or the export profile is set Then the "YouTube" channel preset is auto-applied to the Clip Card And the preset’s default aspect ratio and export specs are set on the timeline and export dialog And switching the destination to "LinkedIn" or "TikTok" auto-applies the respective preset And if the user manually overrides the preset, auto-selection does not overwrite it without explicit confirmation
Safe Zone Enforcement for Overlays and Captions
Given a channel preset with defined text/overlay/caption safe zones is applied When the user places or drags logos, text, captions, or CTAs Then elements snap within and cannot be saved outside the safe zones for the active aspect ratio And auto-generated captions are placed according to the preset’s caption placement rules And overlays and captions never overlap per the preset’s overlap rules And on export, validation blocks export if any element violates safe zones, listing timestamps and elements
Aspect Ratio Switching Preserves Layout
Given a channel preset with safe zones for 16:9, 9:16, and 1:1 is applied When the user switches the aspect ratio between 16:9, 9:16, and 1:1 Then all overlays, captions, and watermarks reflow to remain fully within the new safe zones And no text baseline is truncated or clipped in the preview And no element crosses the preset margins by more than 0 pixels And the before/after bounding boxes of each element are preserved proportionally
Export Spec Compliance Per Channel
Given a channel preset defines export specs (resolution, frame rate, codec/container, bitrate, and platform limits) When the user exports the Clip Card Then the produced file matches the preset specs exactly And if the source content exceeds duration or size limits, the user is prompted to trim or transcode to comply And export is blocked until non-compliance is resolved And the export summary includes a spec-compliance checklist marked Pass for each spec
End-Screen Reserved Area Respect
Given the YouTube preset defines a reserved end-screen area and time window When CTAs, captions, or overlays exist within the reserved window Then the system auto-positions them outside the reserved area without overlap And if auto-positioning is not possible, validation flags the specific conflicts and timestamps and blocks export And presets without end-screen constraints do not apply any reservation
Per-Channel Watermark and CTA Styles
Given the LinkedIn preset defines watermark position and opacity and CTA style When the preset is applied to a Clip Card Then the watermark renders at the configured corner with the configured opacity across all aspect ratios And the CTA adopts the preset style (shape, color, font) and respects safe zones And captions do not overlap the watermark or CTA And changing the channel updates watermark and CTA instantly according to the new preset
Multi-Destination Export Uses Per-Channel Presets
Given the user selects multiple destinations (YouTube, LinkedIn, TikTok) for export When batch export is initiated Then each output uses its own channel preset (safe zones, aspect ratio, export specs) And validation runs per channel before encoding And channels that pass export successfully while failing channels are skipped and reported with reasons And the final report lists pass/fail, file paths, and validation errors per channel
One-Click Apply & Batch Update
"As a creator, I want to apply or change a brand skin across all my clips with one click so that I don’t spend time updating each card manually."
Description

Allow users to apply a selected brand skin to a single Clip Card, a selection, or all cards in a project with one click. Support setting a default skin at workspace/project level, per-card overrides, and bulk updates. Changes should cascade non-destructively to captions, speaker labels, and overlays. Provide undo/rollback for batch operations and an option to re-render affected exports.

Acceptance Criteria
Apply Skin to Single Clip Card
Given a project contains at least one Clip Card and at least one Brand Skin is available When the user selects a Clip Card and clicks "Apply Skin" on Skin X Then Skin X's logo, colors, fonts, and safe areas are applied to the selected card across its configured aspect ratios (16:9, 9:16, 1:1) And existing captions, speaker labels, and overlays remain intact with styles updated only (no timing or text changes) And a visual preview updates within 2 seconds And the action is recorded as a single undo step named "Apply Skin to 1 card"
Batch Apply to Multiple Selected Cards
Given a project with N selected Clip Cards (N >= 2) and Brand Skin Y When the user triggers "Apply Skin to Selection" with Skin Y Then a confirmation modal displays the count of selected cards, estimated time, and cards with per-card overrides And upon confirmation, Skin Y is applied to all non-overridden cards And cards with per-card overrides are excluded unless the user explicitly checks "Override per-card skins" And operation progress is shown with success/failure counts And a single undo step "Apply Skin to N cards" is created
Set Workspace and Project Default Skin
Given workspace settings and project settings support a default Brand Skin When an admin sets Workspace Default to Skin A Then new projects inherit Default Skin A When a project owner sets Project Default to Skin B Then new cards in that project inherit Skin B instead of the workspace default And existing cards are not changed until the owner chooses "Apply Project Default to existing cards" And when applied, only cards without per-card overrides change And the UI indicates the active default skin for the project
Per-Card Override Behavior
Given a Clip Card has an explicit per-card skin override set to Skin C When a project-level default is changed or a batch apply is initiated with Skin D Then Skin C remains applied to that card by default And if the user explicitly selects "Override per-card skins" in the batch action, Skin D replaces Skin C on that card And the override flag is updated to reflect the new explicit skin
Non-Destructive Cascading to Captions and Overlays
Given a Clip Card with captions, speaker labels, and graphic overlays When any skin is applied or changed via single or batch operation Then caption text, timestamps, and segment boundaries remain unchanged And speaker labels remain unchanged And overlay positions are preserved relative to content and constrained within safe areas for 16:9, 9:16, and 1:1 And only style attributes (font family, size, color, background) update per the skin
Undo and Rollback for Batch Operations
Given a completed batch apply operation affected M cards (M >= 1) When the user clicks Undo Then all affected cards revert to their exact previous skins and style states atomically And any queued re-renders for the undone changes are cancelled And Redo reapplies the batch with the original parameters and scope
Re-render Affected Exports After Skin Change
Given exports exist for cards whose skins have changed When the changes are saved Then those exports are marked "Outdated" And the user is prompted to "Re-render affected exports" And upon confirmation, re-render jobs are queued per affected aspect ratio and channel preset And progress and any errors are visible per export And the new exports are versioned, preserving previous files and links
Adaptive Layout Engine
"As a video editor, I want the skin to adapt intelligently to different aspect ratios so that elements are always legible and don’t cover key content."
Description

Implement a rules-based layout engine that auto-scales and repositions skin elements across aspect ratios while preserving brand hierarchy. Enforce safe areas, detect collisions with captions/video content, maintain minimum font sizes, and adapt background treatments (e.g., blur/padding) as needed. Integrate with caption rendering to reserve space and maintain legibility, ensuring consistent, on-brand composition in 16:9, 9:16, and 1:1.

Acceptance Criteria
Cross-Ratio Auto-Scaling Preserves Brand Hierarchy
Given a brand skin with defined element priorities (Logo > Title > Subtitle > CTA > Decorative) and a base layout in 16:9 When the canvas aspect ratio is changed to 9:16 or 1:1 Then each element scales and repositions to its target zone for the new ratio And the visual priority is preserved such that no lower-priority element has a larger font size or occupied area than a higher-priority element And inter-element spacing scales proportionally within ±2% of the relevant canvas dimension And the transformation completes within 150 ms for a 1080p canvas
Safe Area Enforcement per Channel Preset
Given channel presets with safe area insets for YouTube, LinkedIn, and LMS When a clip card is rendered for any preset and aspect ratio (16:9, 9:16, 1:1) Then 100% of element and caption bounding boxes lie inside the configured safe areas with a minimum 8 px margin (±1 px tolerance) And any element initially outside safe areas is auto-adjusted without violating brand hierarchy And a "safe-area-adjusted" flag is recorded in the layout audit log for that render
Collision Detection and Resolution with Captions and Focal Regions
Given per-frame caption bounding boxes and detected focal regions from the analyzer When any skin element’s bounding box intersects a caption or focal region by more than 0 px Then a collision is registered and resolved in this order: nudge up to 24 px, dock to alternate zone, reduce element max width/height down to its configured minimum, hide decorative elements And captions are never obscured and maintain at least 8 px clearance from other elements And after resolution, no collisions remain for that frame
Minimum Font Size and Text Legibility Constraints
Given configured minimum font sizes per text role (e.g., Title, Subtitle, CTA) and max line counts When scaling layouts for any aspect ratio Then no text renders below its minimum font size And text wraps up to the max lines and then truncates with an ellipsis as configured And text over video or images meets WCAG 2.1 contrast ratios (≥4.5:1 for body text, ≥3:1 for large text ≥18pt/14pt bold) And kerning/line-height remain within engine defaults without glyph clipping or overlap
Adaptive Background Treatments for Readability
Given background treatment options (blur plate, brand-color padding, gradient) with configured ranges When measured contrast for a text element falls below threshold or reserved space requires padding Then an adaptive treatment is applied to the element’s plate to meet contrast targets without exceeding the element’s safe zone And Gaussian blur radius, plate opacity, and padding remain within configured min/max And transitions between treatments complete within 100 ms without visible flicker
Caption Integration and Space Reservation
Given a caption style (font size, line height) and a configured maximum of 2 lines When laying out elements for any aspect ratio Then vertical space for captions equal to the configured maximum is reserved and excluded from other element zones And if live captions exceed the reserved lines, non-critical elements are reduced or moved per priority rules without obscuring captions And caption text remains fully visible with at least 8 px padding inside its reserved region
Preview-to-Export Fidelity and Performance
Given layouts previewed at design time and exports at 1080x1920, 1920x1080, and 1080x1080 When exporting the clip card Then element positions in the export match the preview within 1 px and colors match within ΔE ≤ 2 And safe-area and collision constraints remain satisfied in the exported media And initial layout computation completes within 150 ms and subsequent adjustments within 30 ms on the reference device profile
Live Multi-Ratio Preview & QA Checks
"As a producer, I want real-time multi-ratio previews with automated checks so that I can catch issues before publishing."
Description

Provide real-time previews of the applied skin across 16:9, 9:16, and 1:1 simultaneously with timeline scrubbing. Overlay platform safe zones and surface automated QA alerts for contrast ratio, overflow, margin breaches, and minimum text sizes. Include quick toggles for elements, snapshot comparisons, and a preflight checklist before export to reduce rework.

Acceptance Criteria
Real-time Triple Preview with Timeline Scrubbing
Given a clip with an applied Brand Skin and generated captions, When the user scrubs the timeline or plays the video, Then all three previews (16:9, 9:16, 1:1) update within 150 ms of playhead movement and remain frame-synced with ≤1 frame drift at 30 fps. Given the user switches the active channel preset, When brand parameters update, Then all three previews re-render with the new skin within 300 ms without desynchronizing playback. Given render latency exceeds thresholds, When the system detects >300 ms preview lag, Then a non-blocking "Preview catching up" indicator is shown until latency returns under 150 ms.
Platform Safe Zone Overlays per Ratio
Given a selected platform (e.g., YouTube, LinkedIn, LMS) in the channel preset, When the Safe Zones toggle is enabled, Then each ratio preview displays platform-specific safe area overlays with a positional tolerance of ±2 px relative to target resolution. Given the user switches platform within the preset, When Safe Zones are enabled, Then overlays update in <100 ms and each preview shows an overlay label indicating the platform and ratio. Given the Safe Zones toggle is disabled, When the user turns it off, Then overlays are removed from all previews immediately and do not affect export rendering.
Automated QA Alerts: Contrast, Overflow, Margins, Text Size
Given on-canvas text elements, When contrast is computed against the background, Then an alert is raised if contrast ratio <4.5:1 for normal text or <3:1 for large text per WCAG 2.1, and the affected element is highlighted in each ratio. Given any text or logo element, When its bounding box overflows the canvas or breaches safe margins by >1 px, Then an alert is raised specifying ratio, platform, and measured overrun in pixels. Given channel preset constraints, When a text element’s computed size is <preset.minimumTextSizePx for that platform and ratio, Then a minimum size alert is raised with the current and required sizes. Given one or more alerts exist, When the Alerts panel is opened, Then alerts are grouped and filterable by ratio and type, and selecting an alert moves the playhead to the first offending frame and focuses the element.
Element Visibility Toggles Recompute QA
Given element toggles for Logo, Captions, Title, and Decorative Overlays, When an element is toggled off, Then it is hidden in all three previews within 100 ms and any alerts solely caused by that element are dismissed. Given previously hidden elements, When an element is toggled back on, Then previews update within 100 ms and any previously applicable alerts are re-evaluated and reinstated if conditions still fail. Given multiple toggles in succession, When the user toggles three or more elements within 2 seconds, Then the QA system debounces and produces a consolidated alert state within 300 ms after the last toggle.
Snapshot Capture and Side-by-Side Comparison
Given the current playhead time, When the user clicks "Snapshot", Then stills for 16:9, 9:16, and 1:1 are captured with the active skin applied and saved with timestamp, ratio, and channel preset metadata. Given two snapshots are selected, When the user opens Compare, Then a side-by-side comparison is displayed per ratio, with a toggle to show/hide diff overlays for bounding boxes, text content changes, and color differences. Given a snapshot is renamed or deleted, When the user performs the action, Then the snapshot list updates immediately without affecting the source clip or applied skin.
Preflight Checklist and Export Gating
Given the user initiates Export, When Preflight runs, Then the checklist displays per-ratio pass/fail for: no unresolved QA alerts, safe zone compliance, text size ≥preset.minimumTextSizePx, contrast meets WCAG thresholds, and a channel preset is selected. Given outstanding failures, When the user attempts to export, Then Export is disabled until issues are resolved or the user provides a justification and checks an explicit "Acknowledge risks" override, which is stored in export metadata. Given a 10-minute clip, When Preflight executes with no failures, Then the checklist completes in ≤2 seconds and the Export button becomes enabled.
Brand Governance & Permissions
"As a brand guardian, I want permissions and approvals for skins so that our brand isn’t accidentally misused."
Description

Introduce role-based access controls for creating, editing, approving, and applying skins. Allow org admins to lock critical assets, enforce default skins, and restrict font uploads to licensed libraries. Maintain an audit log of changes and applications, support SSO group mapping, and provide policy settings to limit per-card overrides for compliance-sensitive teams.

Acceptance Criteria
RBAC: Create, Edit, Approve, and Apply Brand Skins
Given an organization with roles Admin, Designer, Approver, Editor, Viewer And a brand skin "Blue v1" exists in Draft status When a Designer creates a new skin Then the skin is saved as Draft and is visible to Admins and Designers When a Designer submits "Blue v1" for approval Then the skin status changes to Pending Approval and notifies Approvers When an Approver approves "Blue v1" Then the status changes to Approved and the skin becomes applicable to Clip Cards When an Editor applies "Blue v1" to a Clip Card Then the apply action succeeds only if the skin is Approved When a Viewer attempts to create, edit, approve, or apply a skin Then the action is blocked with HTTP 403 and a UI message "Insufficient permissions" And each allowed or blocked action is recorded in the audit log with actor, action, target, timestamp
Admin Locking of Critical Brand Assets
Given an Admin locks assets Logo:Primary, Palette:Brand, Font:Acme Sans in skin "Blue v1" When a Designer attempts to edit or delete any locked asset Then the operation is blocked with message "Asset is locked by Admin" and HTTP 403 When an Admin unlocks an asset Then the action requires confirmation and is logged with before/after values and actor When "Blue v1" is applied to aspect ratios 16:9, 9:16, and 1:1 Then locked safe areas are enforced consistently and cannot be moved by Editors
Default Skin Enforcement by Channel
Given org default skins are set as YouTube=YT Default v2, LinkedIn=LI Default v1, LMS=LMS Default v3 When a new Clip Card is created with channel=LinkedIn Then "LI Default v1" is auto-applied before the card is first rendered And if policy "Prevent override" is ON for LinkedIn Then skin selection UI is disabled and any API override attempt returns HTTP 403 And if policy "Prevent override" is OFF for LinkedIn Then Editors may change the skin, and the change is recorded in the audit log When a Clip Card has no channel mapping Then the global default skin is auto-applied
Licensed Font Library Enforcement
Given licensed font libraries "Monotype-Org" and "Adobe-Fonts" are connected for the organization When any user attempts to upload a local font file Then the upload is blocked with message "Only licensed library fonts allowed" and HTTP 403 When an Admin adds a new font to the org Then the Admin must select it from a connected licensed library and the system stores vendor and license ID metadata When a font's license is marked expired in the library Then the font becomes unavailable for new skins and any apply action using it is blocked and logged
Comprehensive Audit Logging for Brand Skins
Given audit logging is enabled at the organization level When any skin is created, edited, submitted for approval, approved/rejected, locked/unlocked, applied to a Clip Card, or overridden Then an immutable audit entry is recorded with fields: timestamp (UTC), actor (user ID, name), action, target (skin/card IDs), before/after snapshot, source (UI/API), IP address And audit entries are filterable by date range, actor, action, and target, and exportable to CSV And the system retains audit entries for at least 365 days
SSO Group-to-Role Mapping
Given SSO is configured via SAML or OIDC and IdP groups "Designers", "Approvers", "Editors", and "Viewers" are mapped to roles in ClipSpark When a user signs in via SSO and belongs to "Designers" and "Editors" Then the user is granted the union of permissions for Designer and Editor within 60 seconds of first login When the user is removed from "Designers" in the IdP Then the corresponding permissions are revoked on next login or within 15 minutes via periodic sync, defaulting to Viewer if no mapped groups remain When an unmapped user signs in Then the user is assigned Viewer role and cannot access Admin-only settings
Policy-Controlled Per-Card Overrides
Given an org policy for LinkedIn sets "Allowed overrides: text color" and "Blocked overrides: logo position, fonts, safe areas" When an Editor edits a LinkedIn Clip Card using an approved skin Then the UI allows changing text color within the brand palette only And attempts to move the logo outside the safe area, change fonts, or alter locked elements are blocked with message "Override not permitted by policy" When the Editor submits a one-time exception request for logo position Then the request requires Approver approval; upon approval, the override is applied only to the specified card and an audit entry is recorded
Skin Versioning & Rollback
"As a marketing manager, I want versioned skins with rollback so that we can ship brand updates safely and track what went live."
Description

Version each brand skin with change logs and compatibility notes. Allow assigning specific skin versions per channel/preset, staging updates to subsets of projects, and rolling back if issues are found. Include migration tools to update existing Clip Cards and track which exports used which skin version for auditability.

Acceptance Criteria
Create and Save New Skin Version with Change Log
Given I have a brand skin draft with changes, When I select "Save as new version" and provide a non-empty change log and optional compatibility notes, Then a new immutable version is created with an auto-incremented semantic version (major/minor/patch selectable) and recorded author and timestamp. Given a new version is created, Then it appears in the skin's version history with version number, change log summary (first 160 chars), compatibility notes badge, and is retrievable via API and UI. Given a version exists, When I attempt to edit its assets or settings, Then the system prevents edits and requires creating another version.
Assign Specific Skin Version Per Channel Preset
Given a workspace channel preset (e.g., YouTube 16:9), When I assign skin version vX.Y.Z to that preset, Then all new Clip Cards using that preset are pinned to vX.Y.Z by default. Given a project uses a channel preset with a pinned skin version, When a user creates or re-renders a Clip Card, Then the render uses the pinned version and the version number is visible in the render settings. Given a skin version is unassigned from a preset, When new Clip Cards are created with that preset, Then the system falls back to the workspace default skin version and records the version used.
Stage Skin Update to Subset of Projects
Given skin version vN is the current default for a preset and vN+1 is available, When I create a staged rollout targeting a selected subset of projects (by list selection or percentage), Then only that subset uses vN+1 for new renders and other projects remain on vN. Given a staged rollout is active, Then the system displays rollout progress (projects migrated/total) and allows pause/resume/cancel actions. Given a staged rollout is canceled, Then future renders for affected projects revert to the previously pinned version without changing past exports.
One-Click Rollback to Prior Skin Version
Given skin version vN is assigned to a preset and issues are reported, When I initiate a rollback to version vN-1 and provide a rollback reason, Then all future renders for that preset immediately use vN-1 and the rollback action is logged with actor, timestamp, and reason. Given a rollback occurs, Then previously exported media remain unchanged and display the original skin version used. Given scheduled renders exist that were queued under vN, When rollback to vN-1 completes, Then queued jobs are re-queued to use vN-1 before executing.
Migrate Existing Clip Cards to New Skin Version
Given there are existing Clip Cards pinned to vN, When I run the migration tool to upgrade them to vN+1, Then the system queues re-renders for selected cards and reports counts of succeeded, failed, and skipped items. Given a migration run completes, Then a downloadable report lists each Clip Card ID, previous version, target version, outcome, duration, and error (if any). Given a migration is started, When I select "dry run", Then the tool computes impact and incompatibilities without making changes and outputs the same report fields with "No Change" outcomes.
Export Audit: Track Skin Version Used
Given any export is generated from a Clip Card, Then the export metadata includes the skin version ID and hash and is viewable in the UI and available via API. Given exports exist across versions, When I filter by skin version in the Export History, Then only exports matching the selected version(s) are shown and counts are displayed. Given I export an audit CSV for a date range, Then each row includes export ID, project, channel preset, aspect ratio, skin version, user, and timestamp.
Prevent Incompatible Version Assignment via Preflight Checks
Given a skin version has declared compatibility notes that mark certain presets/aspect ratios as incompatible, When I attempt to assign that version to a conflicting preset, Then the system blocks the assignment with a clear error citing the incompatibility. Given a skin version is missing required assets (fonts/colors/logo variants) for a preset's aspect ratios, When I attempt assignment, Then the system fails preflight and lists missing assets by ratio and channel. Given a skin version has warnings (not blockers), When I proceed with assignment, Then the system requires explicit confirmation and records that an override occurred.

Smart CTAs

Add high-converting calls-to-action directly on cards (Subscribe, Book Demo, Download PDF). Time them to appear at the right moment or keep them persistent, route by audience/channel, and track click-to-conversion—turning views into measurable outcomes.

Requirements

CTA Component Library & Templates
"As a content creator, I want to choose from ready-made CTA templates and style them to my brand so that I can launch effective CTAs quickly and consistently."
Description

Provide a library of prebuilt, high-converting CTA components (Subscribe, Book Demo, Download PDF, Custom) that can be placed on ClipSpark cards and video overlays. Each template supports brand theming, typography, colors, icons/images, and localization. Components are responsive, mobile-safe, and WCAG 2.1 AA accessible with keyboard focus and screen reader labels. Templates support variant states (default/hover/pressed), optional disclaimers, and legal text. Integrates with the project brand kit, asset library, and export pipeline to ensure visual consistency across the ClipSpark web player, shared links, and downloaded assets.

Acceptance Criteria
Brand Theming Across CTA Templates
Given a project with a configured Brand Kit (colors, typography, logo) When any CTA template (Subscribe, Book Demo, Download PDF, Custom) is added to a card or overlay Then the component applies brand color tokens and typography (font family, size scale, weight) automatically And when component-level style overrides are applied Then overrides persist for that component and do not modify the Brand Kit And when switching between CTA templates or variants Then brand theming and component overrides persist without reset And then text-to-background contrast for all CTA text meets WCAG AA (≥ 4.5:1) And icons/logos from the asset library scale to the template-defined size without distortion or pixelation
Responsive and Mobile-Safe CTA Rendering
Given supported viewports (≥1200px, 992–1199px, 768–991px, 480–767px, <480px) When a CTA is rendered on a card or video overlay Then it fits within the player/card safe area without overlapping core controls or captions zones And the minimum tap/click target size is ≥ 44×44 CSS pixels on touch devices And text does not clip; if overflow occurs it truncates with ellipsis per template rules And when orientation or player size changes Then layout reflows within 250 ms with no content loss and CLS ≤ 0.1 And icons/images render crisp on standard and HiDPI displays
WCAG 2.1 AA Accessibility and Keyboard/Screen Reader Support
Given keyboard-only navigation When focus moves through interactive elements Then the CTA receives focus in logical order with a visible focus indicator (contrast ≥ 3:1 against adjacent colors) And when Space or Enter is pressed while the CTA is focused Then the CTA activates exactly once And the CTA exposes an accessible name equal to the visible label (plus action context if needed) And screen readers announce the correct role (button or link), state, and hint text And disclaimers/legal text are reachable, readable, and associated with the CTA for assistive tech And no keyboard traps exist; standard keys navigate in and out of any CTA-related popover
Variant States and Interaction Feedback
Given pointer-capable devices When hovering the CTA Then the hover state renders per design tokens without layout shift And when the CTA is pressed/clicked Then the pressed/active state renders for 100–200 ms and reverts after the action is initiated And on touch devices Then no hover state is shown and pressed feedback appears on touch down And all state transitions complete within 150 ms and preserve AA contrast requirements And when a CTA is configured as disabled (if applicable) Then it is not focusable/clickable and exposes aria-disabled="true"
Localization and RTL Support
Given the project locale is set (e.g., en, es, fr, de, ja, ar) When a CTA template is rendered Then all user-visible strings (label, helper, disclaimer, legal) come from the i18n system And when the locale changes Then strings update without breaking layout and allow at least 30% expansion without overflow And for RTL locales Then layout mirrors (alignment, icon placement, chevrons) and focus order respects RTL conventions And if the brand font lacks required glyphs Then a defined fallback font is used without clipping or tofu characters
Template Content Configuration and Validation
Given the CTA editor When configuring a template Then the user can set label (max 60 chars), optional description (max 140 chars), optional disclaimer/legal text, icon/image, and destination URL/action And when entering a destination Then only valid HTTPS URLs are accepted; invalid entries block save with an inline error And when selecting an icon/image Then only SVG/PNG up to 512 KB are accepted and alt text is required; invalid files are rejected with an inline error And assets can be selected from the Asset Library; if a referenced asset is missing at render time, a neutral placeholder is shown with no layout shift And all validation errors are announced to screen readers and identified to users
Placement on Cards/Overlays and Export Consistency
Given a CTA placed on a card When the card is saved Then the CTA position, alignment, and padding match the on-canvas preview within ±2 px And given a CTA placed as a video overlay with a start and end time When the video plays Then the CTA appears and hides within the specified time window with ±50 ms tolerance And across outputs (web player, shared links, downloaded assets) Then colors, typography, and layout match the editor preview (position variance ≤ ±2 px; color variance ≤ DeltaE 2) And if captions are enabled Then overlay CTAs avoid the captions safe zone or auto-offset by at least 8 px to prevent overlap
Timeline CTA Scheduling
"As a video editor, I want to schedule CTAs to appear at moments of high intent so that viewers see relevant prompts without interrupting the flow."
Description

Enable authors to schedule CTAs to appear at precise timestamps, durations, or persistently across the entire card/video. Supports multiple CTAs per asset with priority and collision rules, safe-zone awareness to avoid covering captions or speaker labels, and snap-to transcript segments. Offers AI-assisted suggestions to surface CTAs near moments of intent (e.g., “book a call”, “download”). Includes preview per device breakpoint and fallback behavior for unsupported players. Stores schedules in project metadata and syncs with rendering and embed SDKs.

Acceptance Criteria
Timestamp/Duration/Persistent CTA Timing
- Given an author sets a CTA with start time 00:12.500 and duration 8.0s, When the video plays from 0s, Then the CTA appears at 12.5s ±100ms and hides at 20.5s ±100ms. - Given playback is paused within the active window, When paused, Then the CTA remains visible; When playback resumes and exits the window, Then the CTA hides within 250ms. - Given a user seeks into an active window (e.g., to 15.0s), When the seek completes, Then the CTA renders within 250ms and the remaining visible time reflects the configured duration. - Given a persistent CTA is configured, When the video plays, seeks, or loops, Then the CTA is visible from 0s to the end of playback and on replay, without flicker (>99% frames show CTA).
Multiple CTAs Priority and Collision Rules
- Given two or more CTAs overlap in time, When priorities are evaluated, Then at most one overlay CTA is visible at a time per breakpoint and the CTA with the lowest priority number (1 is highest) is shown. - Given overlapping CTAs share the same priority, When a collision occurs, Then the CTA with the earlier createdAt is shown and others are deferred. - Given the visible CTA ends, When another eligible CTA remains in the same window, Then the next CTA becomes visible within 250ms according to priority order. - Given collisions exist in the schedule, When viewing the editor timeline, Then each collision is flagged and the currently winning CTA is indicated.
Safe-Zone Avoidance for Captions and Speaker Labels
- Given captions or speaker labels are enabled, When a CTA would overlap their bounding boxes, Then the CTA repositions to the nearest available safe zone with a minimum 8px margin on all sides. - Given no non-overlapping position exists, When the conflict persists across all candidate positions, Then the CTA collapses to a compact pill in a designated safe area and remains clickable. - Given device breakpoints (mobile/tablet/desktop), When safe zones differ, Then the CTA position respects the breakpoint-specific safe zone maps consistently across preview and embed. - Given the user manually drags a CTA into a restricted area, When dropped, Then it snaps back to the nearest safe position within 150ms.
Snap-to Transcript Segments for CTA Anchoring
- Given the author enables Snap-to Transcript, When a transcript segment is selected, Then the CTA start aligns to the segment start within ±200ms and default duration equals the segment’s duration (editable by the author). - Given the transcript is re-aligned (timestamps shift), When the project is reopened or refreshed, Then snapped CTAs update to the new segment boundaries within ±200ms. - Given the selected segment is deleted, When loading the schedule, Then the CTA retains its last resolved times and is marked as Unsnapped for author review. - Given keyboard snapping is used, When nudging left/right, Then the CTA snaps to the nearest segment boundary rather than arbitrary timecodes.
AI-Assisted CTA Suggestions Near Moments of Intent
- Given a processed transcript for a video ≤60 minutes, When the author requests suggestions, Then the system returns ≥5 suggestions within 10 seconds, each including start time, suggested CTA type/label, a rationale excerpt, and a confidence score (0.0–1.0). - Given the author accepts a suggestion, When applied, Then a scheduled CTA is created snapped to the referenced transcript segment with editable fields prefilled. - Given suggestions are inserted, When they overlap existing CTAs, Then standard priority and collision rules apply automatically. - Given suggestion telemetry is enabled, When suggestions are generated/accepted/edited, Then events are logged with IDs to correlate outcomes (no PII).
Breakpoint Preview and Unsupported Player Fallback
- Given the editor preview, When switching between desktop (≥1024px), tablet (768–1023px), and mobile (≤767px), Then CTA timing, position, and safe-zone behavior render accurately for each breakpoint. - Given an embed host that does not support overlay rendering, When a CTA’s active window occurs, Then the SDK surfaces a visible fallback CTA UI outside the video within 500ms that preserves the click path to the configured target. - Given fallback mode is active, When using editor preview, Then authors can toggle a Fallback view that mirrors the embed behavior. - Given the player regains overlay support, When detected, Then the system reverts to native overlay CTAs on the next active window without duplicating UI.
Schedule Persistence and Renderer/SDK Synchronization
- Given the author saves a project, When reloading or publishing, Then all CTA schedules (start, duration, persistent flag, position, priority, snap state) persist in project metadata with a version and lastModified timestamp. - Given the rendering pipeline runs, When producing outputs, Then CTA schedules are applied consistently to overlays or burn-ins per configuration and match editor timings within ±100ms. - Given an embed loads, When the SDK fetches project metadata, Then it renders the same CTA schedule deterministically and reflects published changes within 60 seconds of publish. - Given the public API, When calling GET /projects/{id}/ctas, Then the response includes each CTA with fields: id, start, duration, persistent, position, priority, snappedToSegmentId (nullable), and matches editor state.
Audience & Channel Routing Rules
"As a marketer, I want to route different CTAs based on audience and channel so that each viewer gets the most relevant action."
Description

Allow conditional display and routing of CTAs based on audience and channel: referrer, UTM parameters, campaign, device type, geo, sign-in status, and customer segment. Authors can define rule sets with priority order, A/B variants, and default fallback. Routing can switch CTA copy, destination URL, or action type. Includes test mode and shareable preview links that simulate segments. Rules are evaluated client-side with server-side validation for integrity, and selections are logged for analytics attribution.

Acceptance Criteria
Priority and Fallback Matching for Audience/Channel Rules
Given a published rule set containing multiple rules with unique priority values and a defined default fallback When a viewer matches more than one rule Then the rule with the highest priority (lowest priority number) is selected and executed Given a viewer matches no rule conditions When the rule set is evaluated client-side Then the default fallback CTA variant is displayed and routed Given two rules are assigned the same priority When the author attempts to save or publish the rule set Then server-side validation rejects the configuration with a duplicate priority error and prevents publish Given a rule's priority is changed and republished When a viewer loads the page afterward Then evaluation uses the new priority order on the next page load Given a selected rule changes CTA copy, destination URL, or action type When the rule is applied Then the viewer sees the updated CTA copy, URL, and action type exactly as configured
UTM and Referrer-Based CTA Routing
Given a viewer lands on a URL containing utm_source=YouTube and utm_campaign=Spring (any case, URL-encoded allowed) When a rule targets utm_source=YouTube and campaign=Spring Then that rule matches and its CTA is displayed Given a viewer arrives with a referrer of https://www.twitter.com/somepath When a rule targets referrer domain twitter.com Then the rule matches using the referring domain (scheme and path ignored) Given a viewer with no referrer and no UTM parameters When rules require referrer and/or UTM matches Then those rules do not match and evaluation proceeds to other rules or fallback Given multiple UTM parameters are present When a rule specifies only utm_source Then matching is evaluated only against the specified key(s), not all present parameters
Device and Geo Targeting for CTA Display
Given rules target device types mobile, tablet, and desktop When the viewer device is identified as iPhone Then only device=mobile rules are eligible to match Given a rule targets geo country=US When the viewer's IP resolves to country US via geo lookup Then the rule matches and its CTA is displayed Given geo lookup fails or returns unknown When evaluating a rule that requires a specific geo Then the rule does not match and evaluation continues to other rules or fallback Given a rule targets multiple countries (US, CA) When the viewer is in CA Then the rule matches
Sign-In Status and Customer Segment Routing
Given a rule targets signed_in=true When the viewer has a valid authenticated session token Then the rule matches Given a rule targets signed_in=false When the viewer is anonymous (no valid session) Then the rule matches Given a rule targets customer_segment="Educator" When the viewer's segment context equals Educator Then the rule matches; otherwise it does not Given a rule requires signed_in=false AND customer_segment="Customer" When the viewer is signed in and in segment Customer Then the rule does not match because all conditions must be satisfied
A/B Variant Allocation and Persistence
Given a rule configured with Variant A=60% and Variant B=40% When 1000 qualifying viewers are assigned Then observed assignment is within ±5 percentage points of the configured split Given a viewer is assigned Variant A When the viewer returns within 30 days on the same browser/device Then the viewer consistently receives Variant A (assignment persisted via first-party storage) Given allocation percentages are edited and republished When new qualifying viewers arrive after the change Then they are bucketed using the new split while existing viewers retain their prior assignment until the experiment is reset Given a viewer is assigned a variant and sees the CTA When impression, click, and conversion events occur Then analytics logs events with ruleId, variantId, assignmentId, timestamps, and test=false to enable click-to-conversion attribution Given no stable viewer identifier is available (e.g., incognito mode) When the viewer refreshes the page Then the variant may change and a new assignment is recorded
Test Mode and Shareable Preview Simulation
Given an author enables Test Mode and selects attributes (e.g., geo=UK, device=mobile, utm_source=LinkedIn, segment=Prospect) When the preview page loads Then evaluation is forced to use the selected attributes and the chosen rule/variant is displayed with a visible "Preview" indicator Given Test Mode is active When CTA impressions, clicks, and conversions occur Then analytics events are flagged test=true and excluded from standard attribution metrics Given a generated shareable preview link with an expiry of 7 days When the link is opened before expiry Then the encoded attributes are simulated for that session Given a generated shareable preview link with an expiry of 7 days When the link is opened after expiry Then the link is rejected or falls back to non-test evaluation with no simulation applied
Server-Side Validation and Fail-Safe Behavior
Given an author attempts to publish a rule set When server-side validation detects duplicate priorities, unsupported action types, disallowed URL schemes, or malformed conditions Then publish is blocked and specific error messages identify the offending rules/fields Given the client cannot retrieve a valid signed rule payload or validation token (e.g., network error, invalid signature, expired token) When the page loads Then only the default fallback CTA is shown and no audience-based routing executes Given a rule's destination URL is configured When the author publishes Then the server validates HTTPS and allowed domains; if invalid, publish is blocked Given a runtime evaluation error occurs client-side When rules are being evaluated Then the system logs the error with context and shows the fallback CTA to the viewer
Conversion Tracking & Attribution
"As a growth manager, I want end-to-end conversion tracking for CTAs so that I can measure ROI and optimize campaigns."
Description

Track CTA impressions, clicks, and downstream conversions end-to-end. Support destination-based conversion signals (querystring keys, thank-you URL patterns), webhooks, pixel fires, and native integrations (GA4, HubSpot, Segment, Calendly). Add deduplication, 7-day attribution windows, and cross-session tracking via signed identifiers while honoring privacy/consent and regional data residency. Emit structured events to the ClipSpark analytics pipeline and expose a conversion API for server-side confirmations.

Acceptance Criteria
CTA Impression Logging on Card Visibility
Given a viewer plays a video with a Smart CTA card, When the card is at least 50% visible for 1000 ms, Then emit an Impression event with fields: event_type=cta_impression, cta_id, video_id, session_id, viewer_id_signed, timestamp_ms, visibility_duration_ms, entry_point, device, locale. Given the same card remains on screen, When visibility does not drop below 10% for at least 5000 ms, Then do not emit additional Impression events. Given the card exits view and remains <10% visible for ≥5000 ms, When it re-enters ≥50% visibility for ≥1000 ms, Then emit a new Impression event with a new idempotency_key. Given the network is unavailable when an Impression is generated, When connectivity resumes within 24 hours, Then the queued event is sent exactly-once using idempotency_key; else the event is discarded and an error is logged. Given the viewer has not consented to analytics, When the card becomes visible, Then suppress Impression event or emit only aggregate_increment without viewer_id_signed per consent configuration.
CTA Click Tracking with 7-Day Attribution and Deduplication
Given a CTA is rendered, When the viewer clicks it, Then emit a Click event with fields: event_type=cta_click, cta_id, video_id, session_id, viewer_id_signed, timestamp_ms, click_position, referrer_url, destination_url. Given a viewer clicks the same CTA multiple times within 30 minutes in the same session, When calculating attribution, Then treat the first click as the primary touch and ignore duplicates for deduplicated click counts; still persist raw clicks. Given attribution model=last_click and window=7 days, When a conversion occurs, Then attribute the conversion to the most recent eligible Click event for that viewer within the preceding 7 days; else mark attribution=unattributed. Given consent is withdrawn mid-session, When subsequent clicks occur, Then do not associate viewer_id_signed to Click events and do not attribute conversions to those clicks.
Destination-Based Conversion Detection via URL Patterns and Query Keys
Given a conversion definition with thank_you_url_pattern="https://example.com/thank-you/*" and query_keys=["cs_conv","utm_campaign"], When the viewer lands on https://example.com/thank-you/booking?cs_conv=1&utm_campaign=fall, Then emit a Conversion event with conversion_source=destination, matched_pattern, query_key_values, and attribute per model/window. Given multiple conversion definitions match a URL, When a conversion is detected, Then apply precedence by configured priority; for equal priority, record a single conversion and include all matched definition_ids in metadata. Given the same viewer triggers the same conversion definition multiple times within 24 hours, When deduplication is enabled, Then record only the first unique conversion per event_id or per (url, 5-minute window). Given conversion_value_key="price" is configured and the URL contains price=199, When the event is emitted, Then set conversion_value=199 and currency from default or currency query param if present.
Conversion Webhooks and Pixel Fires
Given a partner posts to POST /v1/conversions/webhook with JSON payload {event_id, cta_id, viewer_external_id, occurred_at, metadata} and header X-ClipSpark-Signature, When the HMAC signature validates against the shared secret, Then accept the event, respond 202, enqueue processing, and emit a Conversion event with source=webhook. Given a duplicate webhook with the same event_id arrives within 7 days, When processing, Then do not create a new Conversion event and return 200 idempotent acknowledgement. Given a pixel URL GET /p/conv.gif?event_id=...&cta_id=... is requested, When parameters validate, Then record a Conversion event and return a 1x1 GIF with Cache-Control: no-store and p95 response time ≤200 ms. Given the webhook payload includes PII fields (email, phone), When processing, Then hash using SHA-256 with salt before persistence and discard raw PII per privacy configuration.
Native Integrations: GA4, HubSpot, Segment, Calendly
Given GA4 is connected with measurement_id and api_secret, When Click or Conversion events occur, Then forward mapped events via GA4 Measurement Protocol with required params (client_id/server_id, event_name, engagement_time_msec) and receive 2xx responses p95 ≤800 ms. Given HubSpot is connected, When a Conversion includes email, Then upsert a contact, associate to the CTA campaign, and append a timeline event; on 429 rate limit, retry with exponential backoff up to 5 attempts and log outcomes. Given Segment is connected, When events occur, Then emit track calls with event names "CTA Impression", "CTA Click", "CTA Conversion" including traits/context; on delivery failure, queue and retry for up to 24 hours. Given Calendly is integrated, When a scheduling webhook indicates an event booked matching a configured CTA, Then emit a Conversion event with conversion_type="meeting_booked" and attribute per model/window.
Cross-Session Tracking with Signed Identifiers and Regional Data Residency
Given a new viewer with analytics consent granted, When first interacting with a CTA, Then set viewer_id_signed as a region-scoped JWT (TTL 7 days) stored in first-party cookie/localStorage with SameSite=Lax and Secure. Given the viewer returns within 7 days, When a Click or Conversion occurs, Then resolve to the same viewer_id_signed and attribute across sessions; after TTL expiry, issue a new id and link only if a server-side confirmation provides a stable external_id. Given the viewer is located in the EU, When events are stored and processed, Then persist and process only in EU-designated infrastructure and block cross-region transfers unless explicit consent exists. Given consent is declined, When generating identifiers, Then store only a session-scoped, non-persistent id and do not link across sessions.
Structured Event Schema and Conversion Confirmation API
Given an event (Impression, Click, Conversion) is emitted, When validated, Then it conforms to schema v1 with required fields: event_id (UUIDv4), event_type, occurred_at (ISO8601), video_id, cta_id, session_id, viewer_id_signed (nullable), source, region, metadata (object). Given the analytics pipeline endpoint is available, When events are sent, Then achieve at-least-once delivery with idempotency via event_id and deliver 99% of events end-to-end within 60 seconds; failures are retried up to 24 hours. Given the Conversion Confirmation API receives POST /v1/conversions with {external_id or event_id, amount, currency, occurred_at, attribution_hints}, When authenticated via OAuth2 client credentials, Then upsert a Conversion idempotently and return 201 with conversion_id. Given a client exceeds 100 requests per minute, When calling the Conversion API, Then respond 429 with Retry-After and perform no side effects.
One-Click Action Integrations
"As a product marketer, I want CTAs to trigger one-click actions with key tools so that users can convert without friction."
Description

Connect CTAs to frictionless actions: Subscribe (YouTube, Apple Podcasts, Spotify, Email list), Book Demo (Calendly/HubSpot Meetings), Download PDF (hosted asset with optional email gate). Support deep links with prefilled context (video ID, timestamp, campaign), in-player modals where permitted, and graceful fallbacks to external tabs. Validate destinations, handle errors, and provide success callbacks to mark conversions. Include rate limiting and link health checks.

Acceptance Criteria
Subscribe CTA Deep Link with Prefilled Context
Given a Subscribe CTA is configured for a supported provider with channel/account identifiers and context (video_id, timestamp, campaign) When a viewer clicks the CTA Then a new window/tab opens using the provider's deep-link URL containing the context parameters (video_id, ts, campaign, source=clipspark) and all parameters are URL-encoded And the click event is recorded with status=clicked and latency <100ms Given the CTA is saved When destination validation runs Then an HTTP HEAD (fallback to GET) completes with a 2xx/3xx within 2s and SSL (https) is enforced But if the response is 4xx/5xx or times out >3s Then activation is blocked and an error "Destination unreachable" is displayed with retry option And if a 3xx redirect occurs, the final resolved URL is stored for health checks
Book Demo via Embedded Scheduler with Fallback and Conversion Callback
Given a Book Demo CTA is configured with Calendly or HubSpot Meetings and embedding is permitted by provider CSP When a viewer clicks the CTA Then an in-player modal opens within 500ms with the embedded scheduler and prefilled fields (name, email) when available And provider receives context (video_id, timestamp, campaign) via query or embed config When the viewer successfully schedules an event Then a success callback is received within 5s including provider, event_id, CTA_id, and viewer_id And exactly one conversion is recorded for the viewer per CTA within a 10-minute window And the modal shows a "Booked" state and closes within 1s But if embedding is blocked or a popup is prevented Then the provider page opens in a new tab with identical context parameters And conversion is still marked upon provider success webhook or success redirect token And if no success is received within 10 minutes, no conversion is recorded
Download PDF with Optional Email Gate and Conversion Tracking
Given a Download PDF CTA is configured with hosted_asset_id and email_gate=true When an anonymous viewer clicks the CTA Then an in-player email capture appears within 300ms and validates RFC 5322 email syntax And on valid submit, the contact is stored and a signed asset URL is generated And the file download starts within 2s Given the viewer is known (email on file) When the viewer clicks the CTA Then the email gate is skipped and the download starts within 1s But if the asset returns 403/404/5xx or the signed URL expires Then an error "Download unavailable" is displayed, no conversion is recorded, and a retry option is offered When the download begins (HTTP 200/206 detected) Then exactly one conversion is recorded for the viewer per CTA within a 10-minute window
Destination Validation and Ongoing Link Health Checks
Given any CTA is created or edited When the CTA is saved Then destination validation enforces https scheme, matches provider allowlist (YouTube/Apple/Spotify/Calendly/HubSpot), and resolves a 2xx/3xx within 2s And on failure (4xx/5xx/timeout>3s), the CTA cannot be toggled Active and a clear error is shown Given a CTA is Active When background health checks run every 15 minutes Then a HEAD/GET is issued to the resolved URL with 3s timeout And after 3 consecutive failures within 60 minutes, the CTA is auto-disabled and the owner is notified And health checks respect provider rate limits with exponential backoff and jitter
Rate Limiting for Clicks and Conversions
Given a viewer interacts with a CTA When the viewer triggers clicks repeatedly Then at most 5 click events per 60 seconds per CTA per viewer are processed; excess are labeled rate_limited and do not fire destinations Given conversion callbacks are received for a CTA and viewer When multiple success callbacks arrive within 10 minutes Then only the first is counted; subsequent ones return 200 OK but do not increment conversions Given a CTA experiences unusually high callback volume When more than 100 conversion callbacks per minute per CTA are received Then excess callbacks return 429 with Retry-After and are logged for review
Error Handling, Fallbacks, and Telemetry
Given a provider API or destination is unavailable or slow When a viewer clicks a CTA Then a user-friendly message is shown within 300ms and the system attempts a graceful fallback (external tab) within 200ms if in-player modal fails And all failures are logged with correlation_id, CTA_id, video_id, channel, and error_code with PII redacted And client auto-retries non-idempotent operations at most 1 time with exponential backoff starting at 500ms Given any CTA interaction occurs When events (click, modal_open, conversion_success, conversion_fail, rate_limited) are emitted Then they are persisted with timestamp (UTC), CTA_id, video_id, viewer_id (if available), and channel, and are queryable within 60s for analytics
CTA Analytics Dashboard
"As a campaign analyst, I want a dashboard of CTA performance by asset and segment so that I can identify winners and iterate."
Description

Provide an analytics view focused on CTA performance across assets, channels, and audience segments. Report impressions, CTR, conversion rate, assisted conversions, time-to-click, and drop-off after display. Enable breakdowns by variant, rule, device, and campaign; trend charts; cohort comparisons; and export to CSV/API. Include goal configuration, anomaly detection alerts, and a per-CTA diagnostics panel that surfaces common issues (low visibility, overlap with captions, broken links).

Acceptance Criteria
Metrics Aggregation and Accuracy
Given CTA event data with impressions, clicks, conversions, assisted conversions, display timestamps, and playback events exist within the selected date range When a user opens the CTA Analytics Dashboard and selects a date range Then the dashboard displays totals for impressions, clicks, CTR, conversion rate, assisted conversions, median time-to-click, and drop-off-after-display for the selection And CTR equals clicks divided by impressions, shown to two decimal places as a percentage And Conversion Rate equals conversions divided by clicks, shown to two decimal places as a percentage And Assisted Conversions follow the platform’s attribution model and window as labeled in the UI, and the label is visible And Median Time-to-Click is computed as click time minus first display time in seconds, excluding clicks occurring more than 24 hours after display And Drop-off-after-display is the percentage of viewers who stop playback or scrub past the CTA within 5 seconds of first display, out of viewers who saw the CTA And the totals match the sum of underlying events within 0.1% for counts >= 1000 and exactly for counts < 1000
Filter and Breakdown Controls
Given a user has selected filters for asset(s), channel(s), audience segment(s), rule(s), and date range When the user applies a breakdown by variant, rule, device, or campaign Then the dashboard updates within 2 seconds for datasets up to 100k events and shows a table with one row per breakdown value plus an "Other" bucket if more than 20 categories exist And each breakdown row displays all core metrics and the totals equal the sum of visible rows for the selected metric And selecting a row drills down to the per-CTA view for that value, preserving filters And applied filters and breakdown selections persist when navigating between summary, trend, and diagnostics views
Trend Charts and Anomaly Alerts
Given the user views trend charts on the dashboard When the user selects a metric (Impressions, CTR, Conversion Rate, Assisted Conversions, Time-to-Click, or Drop-off) and a granularity (hourly, daily, weekly) Then a time series renders for the selected metric over the date range with tooltips showing value and interval And enabling "Compare to previous period" overlays the prior period with distinct styling and a delta indicator And anomaly detection flags points where the metric deviates by more than 3 standard deviations from a 30-day rolling baseline with at least 500 impressions, and displays an in-chart marker and an entry in the Alerts panel And users with alerts enabled receive an email within 5 minutes of an anomaly with metric, magnitude, timeframe, filters, and a link back to the dashboard
Cohort Comparison View
Given the user opens the Cohort Comparison view When the user defines two or more cohorts by audience segment, channel, campaign, device, or first-view week and applies the same date range Then the dashboard displays side-by-side metrics per cohort with normalized CTR and conversion rate and per-1000-impressions rates And the user can sort by any metric and toggle which metrics to display And the cohort definitions are shown above the table and can be edited, and edits recompute within 2 seconds for datasets up to 100k events
Export to CSV and API
Given the user has applied filters, breakdowns, and a date range When the user clicks Export CSV Then a CSV downloads containing one row per breakdown (or per CTA if no breakdown) with columns for asset, channel, audience segment, variant, rule, device, campaign, date/granularity (if trended), impressions, clicks, CTR, conversions, conversion rate, assisted conversions, time-to-click (median seconds), and drop-off rate, using UTF-8 encoding and the workspace timezone And counts in the CSV match the on-screen values within 0.1% for counts >= 1000 and exactly for counts < 1000 And when the user uses the API endpoint with a valid token and identical filters, the JSON response returns the same dataset with pagination and a 200 status; invalid tokens return 401 and excessive requests return 429 with retry-after headers
Goal Configuration and Progress Indicators
Given the user configures a goal with a target metric (CTR, Conversion Rate, Conversions, Assisted Conversions) for selected CTAs or campaigns and a target date When the goal is saved Then the dashboard shows a goal card with current progress, projected outcome, and status badges On Track (>=95% projected to target), At Risk (70-94.99%), or Off Track (<70%) And editing or pausing the goal updates the projection and status immediately and records a history entry time-stamped to the workspace timezone And goals persist across sessions and are included in exports via a goals column indicating goal_id and status
Per-CTA Diagnostics Panel
Given the user opens the diagnostics panel for a specific CTA When the system analyzes visibility, layout, and destination health for the selected date range Then the panel lists detected issues with severity and evidence, including: - Low visibility when fewer than 30% of impressions have viewable duration >= 2 seconds - Overlap with captions when the CTA’s bounding box overlaps captions for >10% of its on-screen time - Broken link when the CTA destination returns HTTP 4xx/5xx or DNS errors in the last 24 hours And the panel provides remediation suggestions and a "Test Link" action that performs an on-demand check and shows pass/fail with HTTP status And diagnostics compute and render within 1 second for a single CTA and reflect the current filters
CTA Authoring & Preview Editor
"As a producer, I want an intuitive editor to author, preview, and publish CTAs so that I can manage changes safely and efficiently."
Description

Deliver an in-product authoring experience to create, edit, and preview CTAs. Offer drag-and-drop placement on cards/timeline, inline copy editing, variant management, and reusable presets. Provide instant previews across player skins and breakpoints, accessibility checks, and validation for missing links or invalid rules. Support roles/permissions, version history, change audit trails, and draft/publish workflows. Changes propagate via the embed SDK and are reflected in analytics with version identifiers.

Acceptance Criteria
Instant Preview Across Skins/Breakpoints with Accessibility Checks
Given an Author with edit permissions is in the CTA Editor When the user edits CTA copy, styles, or placement Then the inline preview updates within 500 ms without a full page reload And when the user toggles Player Skin (Light, Dark, Minimal) and Breakpoint (360, 768, 1024, 1440) Then the CTA remains fully visible, non-overlapping with player controls, and scroll-free in each preview And when Accessibility Check is run automatically Then all CTA text and buttons meet WCAG AA contrast (>= 4.5:1), each actionable element has a programmatic name, and a visible focus state is shown And keyboard navigation can reach and activate the primary CTA using Tab/Shift+Tab and Enter/Space in the preview And publishing is blocked while any accessibility errors remain; warnings allow publish with explicit confirmation
Drag-and-Drop Placement on Cards and Timeline
Given an Author is placing a CTA onto a card and the video timeline is visible When the user drags the CTA to the timeline Then the start time snaps to 0.5-second increments and the duration can be resized with a minimum of 1 second And autosave persists the placement within 2 seconds of drop and shows a Saved indicator And keyboard repositioning adjusts start time by 0.1s with Arrow keys and by 1s with Shift+Arrow; Undo/Redo (Ctrl/Cmd+Z, Ctrl/Cmd+Y) works for the last 20 actions And if a placement would overlap another CTA in the same anchor position at the same time Then the editor prevents the drop and displays a conflict message with the conflicting CTA name and time range
Inline Copy Editing and Field Validation
Given an Author is editing CTA text inline When the user edits Headline, Body, Button Label, and Destination URL Then live character counters enforce limits (Headline: 120, Body: 280, Button Label: 30) and prevent input beyond the limit And Destination URL must be a valid http(s) URL; invalid input shows an inline error and disables Publish And required fields (Button Label, Destination URL) must be populated to enable Publish; Save Draft remains enabled And on Save Draft or Publish, validation runs; errors highlight the specific fields and success shows a toast confirmation within 1 second
Variant Management and Audience/Channel Routing
Given an Editor is configuring CTA variants When the user creates variants (up to 10 per CTA) and defines routing rules by Audience Segment, Referrer Domain, UTM Source/Medium, and Channel Then exactly one Default variant is required and used as fallback when no rules match And the Rule Simulator allows setting a test context and shows the selected variant deterministically And conflicting or overlapping rules are detected; the system requires a resolved priority or disallows Publish until conflicts are fixed And deleting a variant that is referenced by a rule requires reassignment to another variant before deletion
Reusable CTA Presets Library
Given an Editor wishes to reuse a CTA design When the user saves the current CTA as a Preset with Name and optional Tags Then the Preset stores layout, styles, and copy fields but excludes timeline placement and routing rules And applying a Preset to a new CTA populates fields instantly without overwriting unsaved changes unless confirmed And the Presets library supports search by name/tag, duplicate, and soft-delete; soft-deleted presets cannot be applied and are hidden by default And only Editors/Admins can create or delete presets; presets used by Published CTAs cannot be hard-deleted
Roles, Permissions, Workflow, and Audit Trail
Given role-based access control is enabled When an Author creates or edits a Draft CTA Then they can Save Draft but cannot Publish; Editors/Approvers can Publish And workflow states are Draft → In Review → Published → Archived with allowed transitions; Publish increments a semantic version (e.g., 1.0.0 → 1.1.0) And Version History allows viewing, comparing field-level changes, and Reverting, which creates a new Draft from the selected version And every Save/Publish writes an audit record (actor, timestamp, action, version, fields changed) retrievable via the Audit Trail view and API
Post-Publish Propagation via Embed SDK and Analytics Versioning
Given a CTA is Published with a new version When an embedded player loads or the SDK next polls for config Then the latest CTA configuration including versionId is delivered and applied within 60 seconds, and the SDK emits a ctasUpdated event And viewer interactions generate analytics events (impression, click) containing ctaId, variantId, versionId, playerSkin, and breakpoint And analytics reflect the new version in dashboards within 5 minutes and support filtering by versionId for CTR and click-to-conversion metrics

A/B Variants

Auto-generate and test multiple versions of card headlines, thumbnails, and waveform styles. Split traffic, surface statistically significant winners based on CTR and watch-time, and auto-promote the best performer—boosting engagement with data-backed creative.

Requirements

Auto Variant Generation
"As a content creator, I want the system to auto-generate multiple on-brand headlines, thumbnails, and waveform styles so that I can rapidly test different creative without manual design work."
Description

Automatically generate multiple creative variants for card headlines, thumbnails, and waveform styles from a single source video using AI prompts and brand presets. Supports configurable variant counts, style templates, and content constraints (length, tone, keywords). Pulls context from ClipSpark transcripts, timestamps, and highlights to ensure relevance. Produces render-ready assets with consistent naming, metadata, and linkage back to the originating clip. Enables manual edits and locking of specific elements per variant before launch.

Acceptance Criteria
Configurable Variant Counts Per Asset Type
Given a source clip with transcript, timestamps, highlights, and an active brand preset And the user sets variant counts: headlines=5, thumbnails=3, waveforms=4 When the user clicks "Generate Variants" Then the system produces exactly 5 headline, 3 thumbnail, and 4 waveform variants And each variant is linked to the source clip and appears grouped by asset type in the Variants panel And the API response includes counts per type that match the requested counts
Enforcement of Content Constraints for Headlines
Given content constraints: max_length=60 characters, tone="authoritative", include_keywords=["AI","productivity"], exclude_keywords=["clickbait"] When headline variants are generated Then every headline variant length is <= 60 characters And each headline contains all include_keywords and contains none of the exclude_keywords And each headline passes tone validation for "authoritative" And any headline that fails a constraint is flagged as "Constraint Failed" and not marked render-ready
Application of Brand Presets and Style Templates
Given a brand preset specifying fonts, color palette, and logo And selected style templates: Thumbnail="Clean Thumb v2", Waveform="Minimal Wave v1" When thumbnail and waveform variants are generated Then all variants apply the brand preset fonts, colors, and logo And the selected style templates are used for composition of the respective asset types And no variant includes assets outside the brand preset (e.g., unapproved fonts/colors)
Context-Aware Variant Generation from Transcripts and Highlights
Given the source clip’s transcript segments and highlight timestamps are available When variants are generated Then each headline is derived from specific transcript spans and the span {startMs,endMs} is stored in variant metadata And each thumbnail frame is selected within ±2 seconds of a highlight timestamp (or the transcript span midpoint if no highlight) And variant metadata includes highlightId (when used) and transcript span references for auditability
Render-Ready Assets with Consistent Naming and Metadata Linkage
Given generation completes without errors When assets are saved Then thumbnails are exported as PNG (or JPG if configured) and waveform videos as MP4 using template-defined resolution and aspect ratio And filenames follow the naming template from the brand preset or default to {clipId}_{assetType}_v{index}.{ext} And metadata includes variantId, sourceClipId, assetType, brandPresetId, templateId, generatedAt (ISO 8601), transcriptSpan, and constraints summary And each variant is accessible via a public (or authenticated) URL and is linked to the originating clip in UI and API
Manual Edits and Element Locking Prior to Launch
Given variants are generated and not yet launched When the user edits a variant’s headline text, thumbnail overlay text, or waveform color/shape Then changes are persisted and reflected in both UI and API When the user locks a specific element on a variant Then subsequent regenerate actions for that asset type do not modify the locked element And locked elements are visibly indicated and return locked=true in the API until unlocked by the user
Preflight Validation and Graceful Failure Handling
Given required inputs include an active brand preset and an available transcript (or approved alternative context) When the user starts generation with any missing or invalid required input Then the system blocks generation and displays specific error messages identifying each missing/invalid input And no partial assets are created or stored And the user can correct inputs and retry without residual side effects from the failed attempt
Experiment Setup & Traffic Allocation
"As a marketer, I want to configure how traffic is split across variants and ensure viewers see the same variant on repeat visits so that results are fair and reliable."
Description

Provide an experiment builder to bundle selected variants into an A/B test with configurable traffic splits (e.g., equal, weighted), minimum sample sizes, and runtime limits. Enforce sticky assignment per viewer via cookie or user ID, with fallbacks for anonymous traffic. Support channel-specific allocation (ClipSpark Share Pages, embedded player) and an optional holdout/control. Validate experiment readiness (asset availability, tracking enabled) and prevent overlapping tests on the same asset and placement.

Acceptance Criteria
Experiment Builder Saves Variants and Weighted Splits
Given I have selected at least two variants for a single asset and placement When I set traffic weights that sum to 100% (e.g., 50/30/20) Then the UI validates the sum equals 100% and enables Save And the saved experiment persists the exact weights and variant order And an error is shown if the weights do not sum to 100% or any weight is < 0% And an error is shown if fewer than two variants are included And after 1,000 eligible impressions per channel, the observed allocation per channel is within ±2 percentage points of the configured weights
Sticky Assignment via User ID and Cookie Fallback
Given a running experiment with configured variants When a signed-in viewer with a stable user ID is exposed across sessions and devices Then the same variant is consistently served for that experiment and channel And the assignment key is deterministic from experiment ID + channel + user ID Given an anonymous viewer with cookies enabled is exposed across sessions on the same device When the viewer returns within 30 days Then the same variant is served using a first-party cookie Given an anonymous viewer without cookies or with blocked storage When they start a new session Then a session-scoped variant is used and may change on subsequent sessions And variant assignment occurs before any tracking beacons are fired
Configurable Minimum Sample Size and Runtime Limit Enforcement
Given I configure a minimum sample size per variant (impressions) and a minimum runtime (e.g., 7 days) When the experiment is running Then the system prevents manual conclusion until both the minimum sample size for all active variants and the minimum runtime are met And the UI displays live counts toward each threshold per variant and overall Given I also set a hard runtime limit (e.g., 21 days) When the hard limit elapses Then the system automatically stops new traffic allocation to the experiment and marks it as Ended And any attempt to extend runtime after the hard limit is blocked with an explanation
Channel-Specific Traffic Allocation
Given I select ClipSpark Share Pages and Embedded Player channels for an experiment When I configure separate traffic splits per channel Then each channel stores and applies its own weights And only traffic from the selected channels is eligible for assignment And users on non-selected channels always receive the default experience (no experiment) And after 1,000 eligible impressions per selected channel, the observed allocation per channel is within ±2 percentage points of that channel’s configured weights
Optional Holdout/Control Group
Given I add a Control group to an experiment When I assign a non-zero weight to Control Then Control is treated as a variant with its own sticky assignment and metrics And Control serves the baseline asset without experimental changes And the system prevents removing Control after the experiment starts And Control is included in sample size and runtime calculations
Experiment Readiness Validation at Start
Given I attempt to start an experiment When asset availability is verified for all variants and placements And tracking for CTR and watch-time is confirmed as enabled for the selected channels And embed integrations are verified to include the required tracking script Then the Start button is enabled Given any check fails (e.g., missing thumbnail, disabled tracking, invalid weights) When I attempt to start Then the system blocks start and lists each failing check with remediation hints
Overlap Prevention for Same Asset and Placement
Given an experiment for Asset X and Placement Y is Running or Scheduled When I attempt to create or start another experiment that targets Asset X and Placement Y with any overlapping channel Then the system blocks creation/start and references the conflicting experiment by name and status And if the conflicting experiment is Ended or Canceled, creation/start is allowed And if I change the placement, asset, or channels to remove overlap, creation/start is allowed
Event Tracking & Metrics Attribution
"As a data-informed creator, I want accurate CTR and watch-time tracked per variant so that I can trust the results of my experiments."
Description

Instrument impression, click, play, and watch-time events across ClipSpark Share Pages and the embedded player, attributing each event to a unique experiment and variant. Calculate CTR (clicks/impressions) and normalized watch-time (e.g., average seconds watched or percent watched) with bot filtering and session de-duplication. Provide UTM propagation and referrer capture for segment analysis. Ensure near-real-time aggregation and data quality checks before analysis.

Acceptance Criteria
Variant Attribution on All Events
Given an active A/B experiment with defined variants and a visitor assigned a variant via bucketing When the visitor loads any ClipSpark Share Page or embedded player Then all emitted events (impression, click, play_start, play_progress, play_complete) include experiment_id and variant_id matching the assigned variant Given the same visitor returns within the experiment window When a new session begins Then the visitor is reassigned to the same variant and event attribution remains consistent across sessions and surfaces Given events are stored in analytics When records for experiment-enabled assets are inspected Then experiment_id and variant_id are non-null and valid for ≥ 99.9% of events
Viewable Impression Tracking
Given a card/headline/thumbnail is rendered on a Share Page or embedded player When ≥ 50% of the card enters the viewport for at least 1 second Then exactly one impression event is recorded per session per card with a correlation_id Given the user scrolls away and back within the same session When the card becomes viewable again Then no additional impression is recorded for that card in that session Given an impression event is recorded When it is persisted Then it contains page_type, asset_id, experiment_id, variant_id, correlation_id, referrer, UTM params (if present), and ISO 8601 timestamp
Click Event Tracking and CTR Computation
Given a viewable impression exists in the current session When the user clicks the thumbnail, headline, or primary CTA associated with the card Then a click event is recorded once per unique clickable target per session with correlation_id matching the impression Given impression and click events are aggregated by experiment_id and variant_id When computing CTR for a selected time window and environment Then CTR = unique_clicks / unique_impressions, excluding events flagged as bots Given hourly rollups are generated When latency is measured Then CTR aggregates are available within 2 minutes (P95) of event time
Play Events and Normalized Watch-Time Measurement
Given the Share Page or embedded player is visible When the user initiates playback Then a play_start event is recorded with start_position and correlation_id Given playback continues When every 5 seconds OR every 5% of total duration (whichever is smaller) elapses Then a play_progress event is sent with cumulative_seconds_watched and percent_watched Given playback ends or 30 seconds of inactivity occurs When the session is closed Then a play_complete event is recorded and session watch-time is finalized Given events are aggregated per experiment_id and variant_id When normalized watch-time is computed Then both average_seconds_watched and average_percent_watched are produced with session_count and bot traffic excluded
Bot Filtering and Session De-duplication
Given incoming events are received When user-agent matches a maintained bot list, headless indicators are detected, or abnormal interaction rates (>20 impressions per IP per minute) occur Then the events are flagged as bots and excluded from CTR and watch-time metrics Given multiple identical events (same session_id, asset_id, event_type) occur within 10 minutes When de-duplication runs Then only the first event is retained for metrics; duplicates remain stored but marked deduped Given a user navigates away and returns within 30 minutes When sessionization occurs Then events are attributed to the same session_id for attribution and de-duplication
UTM Propagation and Referrer Capture
Given a visitor lands with UTM parameters in the URL When navigating to the Share Page and loading the embedded player Then utm_source, utm_medium, utm_campaign, utm_content, and utm_term are persisted and attached to all subsequent events Given the player is embedded on a third-party site When events are emitted Then document.referrer domain and path are captured and stored with the event Given UTM values exceed length limits or contain detectable PII (e.g., email patterns) When events are stored Then values are truncated to 256 characters and PII-like values are hashed
Near-Real-Time Aggregation and Data Quality Gates
Given events are ingested into the pipeline When end-to-end latency is measured Then P95 time from event creation to availability in variant-level aggregates is ≤ 2 minutes and P99 ≤ 5 minutes Given a variant has fewer than 100 unique impressions in the last 24 hours When auto-promotion is evaluated Then the variant is marked "insufficient data" and excluded from winner selection Given hourly data quality checks run When completeness and integrity are measured Then missing required fields rate < 0.5%, estimated event loss < 0.1%, and timestamp skew > 5 minutes occurs in < 0.5% of events; otherwise the experiment is flagged "Data Quality Warning" and excluded from analysis
Statistical Significance & Winner Selection
"As a product owner, I want the system to identify statistically significant winners with clear confidence levels so that I can make data-backed creative decisions."
Description

Implement a statistical engine to determine winning variants using configurable methods (e.g., Bayesian or frequentist), minimum detectable effect, and significance thresholds. Support multi-metric optimization with a primary metric (CTR or watch-time) and guardrails (e.g., bounce rate). Include sequential testing with stopping rules, sample size projections, and A/A sanity checks. Output clear result states (inconclusive, trending, winner) with confidence and expected uplift.

Acceptance Criteria
Frequentist Winner Determination (CTR)
Given an A/B test with primary metric CTR, frequentist two-sided test with alpha=0.05, MDE=5% relative, and computed minimum sample size per variant N is met When the observed relative uplift in CTR of the leading variant over control is ≥ 5% and the p-value for the difference is < 0.05 Then result.state="winner", result.winner=the variant with higher CTR, result.confidence=1 - p_value, result.expected_uplift=observed relative uplift with 95% CI, and decision metadata records method="frequentist", alpha=0.05, test_type="two-sided", mde=0.05 And if p-value ≥ 0.05 or uplift < 5% after reaching maximum planned sample size, then result.state="inconclusive" and no winner is selected
Bayesian Winner Determination (CTR or Watch-time)
Given a test configured with method=Bayesian, a neutral prior, posterior threshold τ=0.95 for uplift ≥ MDE, MDE=5% relative (CTR) or 3% relative (watch-time), and minimum sample size N is met When P(uplift ≥ MDE | data) ≥ 0.95 for a variant versus control Then result.state="winner", result.winner=that variant, result.confidence=P(uplift ≥ 0 | data), result.expected_uplift=posterior mean uplift with 95% credible interval, and decision metadata includes method="bayesian", threshold=0.95, prior details, and mde And if P(uplift ≥ MDE | data) < 0.95 at the maximum planned sample size, then result.state="inconclusive"
Multi-Metric Winner with Guardrails
Given a test with a selected primary metric (CTR or Watch-time) and guardrails configured (e.g., bounce_rate relative increase ≤ 2%, average_watch_time relative decrease ≤ 3%) When a variant satisfies the winner condition on the primary metric per the chosen method and all guardrails are within their thresholds Then declare the variant as winner, set result.state="winner", and record guardrail_status="passed" for each guardrail with observed deltas And if any guardrail is violated (e.g., bounce_rate increase > 2% or watch_time decrease > 3%), then result.state="fail-guardrail" and no winner is selected; guardrail name, threshold, and observed delta are reported
Sequential Testing & Stopping Rules
Given sequential testing is enabled with up to 5 interim looks and (frequentist) a Pocock alpha-spending plan controlling overall α=0.05, or (Bayesian) stopping threshold τ=0.95 When (frequentist) an efficacy boundary is crossed at any look, or (Bayesian) P(uplift ≥ MDE) ≥ 0.95 for two consecutive looks Then stop the test and set result.state="winner" (subject to guardrails) and include stopping_reason, look_number, and α_spent (frequentist) or posterior summary (Bayesian) And when (frequentist) a futility boundary is crossed, or (Bayesian) P(uplift ≥ MDE) ≤ 0.10 for two consecutive looks Then stop the test and set result.state="inconclusive" with stopping_reason logged
Sample Size Projection & Time-to-Completion
Given baseline estimates for the primary metric (e.g., CTR=4% or average_watch_time=120s), desired power=80%, significance α=0.05, and MDE=5% (CTR) or 3% (watch-time) When the experiment is configured Then the system outputs required per-variant sample size N with all input assumptions (baseline, variance/rate, power, α, MDE) and the computation method And shows a time-to-completion estimate based on current daily traffic per variant, updated at least daily, and during the test displays percent progress toward N using observed pooled variance/rate
A/A Sanity Check
Given an A/A test where both variants are identical and primary metric is CTR with α=0.05 (frequentist) and τ=0.95 (Bayesian) When the test reaches the computed minimum sample size N or an early-stop rule triggers Then result.state="inconclusive", no winner is selected, and observed absolute uplift |Δ| < MDE is reported And the system logs sanity_check=true with p-value and Bayesian posterior summaries for auditability
Result States, Trending, and Reporting
Given an active test that has not yet met winner criteria When at least 50% of required N is accrued and either (frequentist) 0.05 ≤ p-value < 0.20 with observed uplift ≥ 50% of MDE, or (Bayesian) 0.80 ≤ P(uplift ≥ MDE) < 0.95 Then set result.state="trending" and display projected time-to-decision and sample remaining And when winner conditions are met, set result.state="winner"; when maximum planned N is reached without meeting thresholds or a futility rule triggers, set result.state="inconclusive" And all states include method, parameters, confidence/probability, expected uplift with interval, guardrail summary, and next recommended action
Auto-Promote Winner & Rollback Controls
"As a campaign manager, I want the best-performing variant to be auto-promoted with the option to override or roll back so that I can optimize engagement without constant monitoring."
Description

Enable automatic promotion of the winning variant once significance and minimum sample thresholds are met, switching new traffic to the winner while preserving experiment data. Provide manual override, scheduled promotion, and instant rollback to previous default. Log all changes with timestamps and actor details. Notify stakeholders upon promotion or rollback via in-app and email alerts.

Acceptance Criteria
Auto-Promotion on Significance and Min Sample
Given an active A/B experiment with auto-promotion enabled and configured significance level α and minimum sample size per variant And CTR or watch-time is selected as the primary goal And each variant has sample size greater than or equal to the configured minimum And the leading variant’s improvement is statistically significant at p ≤ α for the selected goal When significance is reached Then the system marks the leading variant as Winner and sets its promotion status to Auto-Promoted And no promotion occurs if the result is a tie or p > α And no promotion occurs if the experiment is Paused
Traffic Routing Switch and Data Preservation
Given a variant has been promoted (auto or manual) When the promotion is committed Then 100% of new traffic is routed to the winner within 120 seconds by default And if a ramp percentage is configured, new traffic follows the configured ramp curve And existing users retain their originally assigned variant for session continuity And all historical experiment data remains accessible and unchanged And metrics collection continues for reporting across all variants
Manual Override to Promote or Block Auto-Promotion
Given a user with Admin or Project Owner role views an active experiment When the user selects a variant and clicks Promote Now Then the selected variant becomes the default for new traffic within 120 seconds And the change is recorded as Manual in the audit log When the user toggles Block Auto-Promotion Then the system prevents auto-promotion regardless of significance until the block is lifted And the UI reflects the current auto-promotion state
Scheduled Promotion Execution
Given a user with Admin or Project Owner role schedules a promotion for a specific date, time, and timezone When the scheduled time is reached Then the selected variant is promoted within 60 seconds And if the experiment is Paused or the variant no longer exists, the promotion is skipped and an error notification is sent And the schedule is visible on the experiment timeline and can be canceled prior to execution
Instant Rollback to Previous Default
Given a previously promoted winner and a prior default variant exist When a user clicks Rollback Now Then the prior default becomes the default for new traffic within 60 seconds And any active promotion schedules are canceled And experiment and variant metrics remain intact and accessible And the rollback action is idempotent; repeated requests do not create additional state changes
Comprehensive Audit Logging of Changes
Given any promotion, scheduled promotion, cancellation, manual override, or rollback occurs When the action is committed Then an immutable audit log entry is written including UTC timestamp, actor user ID and name, action type, experiment ID, prior default variant ID, new default variant ID, trigger source (auto/manual/scheduled), configured thresholds, observed p-value, and sample sizes at the time of decision And the log entry is visible in the experiment timeline UI and retrievable via API
Stakeholder Notifications for Promotion/Rollback
Given in-app and email notifications are enabled for project stakeholders When a promotion or rollback occurs (auto, manual, or scheduled) Then an in-app notification is delivered to all project members with access within 15 seconds And an email is sent to configured recipients within 2 minutes And notifications include action type, actor, experiment name, winner/previous default, trigger source, timestamp, and a link to details And notifications respect user-level preferences and are deduplicated within a 5-minute window
Experiment Dashboard & Reporting
"As a team lead, I want a centralized dashboard with clear experiment results and insights so that my team can quickly act on what works."
Description

Deliver a dashboard to create, monitor, and analyze experiments, showing variant performance over time, segmentation (device, source, geography), and confidence intervals. Include filters, annotations (e.g., publish dates), and export to CSV/PNG. Provide per-experiment summaries, historical comparisons, and an activity audit trail. Surface actionable recommendations and health checks (e.g., underpowered tests, uneven traffic).

Acceptance Criteria
Experiment Creation & Configuration
- Given I have A/B Variants access and a connected project, When I open the Experiment Dashboard and select "Create Experiment", Then I can enter an experiment name (2–80 chars), select target asset(s), and choose up to 5 variants with unique names. - Given I configure variants, When I set traffic splits, Then the splits must sum to 100% with per-variant minimum 5% and inline validation errors shown within 100 ms if invalid. - Given I select metrics, When I choose the primary metric, Then options include CTR and Avg Watch-Time, with exactly one primary and optional secondaries saved to the experiment. - Given I set timing, When I choose "Start now" or a future start date/time (with timezone), Then the experiment status becomes "Running" or "Scheduled" respectively and is persisted (HTTP 201) within 2 s. - Given I save, Then the experiment appears in the dashboard list with correct configuration and an initial sample size of 0 within 5 s.
Time-Series Performance & Confidence Intervals
- Given an experiment with traffic, When I view its detail page, Then a time-series chart displays daily metrics for each variant for the selected date range. - Given the chart is rendered, Then CTR and Avg Watch-Time series include 95% confidence intervals per point and a legend indicating control vs variants. - Given I hover a point, Then a tooltip shows date, variant, impressions, clicks, CTR, avg_watch_time_sec, and CI low/high to 2 decimal places. - Given sparse data days, Then the series shows gaps (no interpolation) and totals remain accurate for the range. - Given a variant achieves 95% significance vs control on the primary metric, Then the chart visually marks significance on the first date it occurs.
Segmentation, Filters & Annotations
- Given I open an experiment, When I apply segment filters (device: desktop/mobile/tablet, source: organic/referral/paid, geography: ISO country), Then charts and tables update within 2 s and all metrics reflect only the filtered traffic. - Given filters are applied, Then the current state is encoded in the URL and restored when the link is shared or reloaded. - Given I need an event marker, When I add an annotation with title, date/time, and type (publish, creative change, external event), Then it appears as a vertical line with label on the chart and can be toggled via legend. - Given an annotation exists, When I edit or delete it, Then the change is versioned and recorded in the audit trail.
CSV and PNG Export (Filter-Respecting)
- Given a report view with filters and date range, When I click "Export CSV", Then a CSV downloads within 5 s containing one row per variant per day with columns: experiment_id, variant_id, variant_name, date, impressions, clicks, CTR, avg_watch_time_sec, ci_low, ci_high, device, source, country (if filtered, column values reflect filter or "ALL"). - Given a chart is visible, When I click "Export PNG", Then a 2x-resolution PNG including the current chart, legend, date range, active filters, and annotations downloads within 5 s. - Given an export completes, Then file names are prefixed with experiment slug and timestamp and match the data shown on screen.
Per-Experiment Summary & Historical Comparison
- Given an experiment has accumulated data, When I view the Summary tab, Then I see control and variant metrics for the primary metric, relative lift vs control, 95% CI, sample sizes, and time elapsed. - Given winner determination, When a variant reaches 95% statistical significance on the primary metric with positive lift and no critical health-check failures, Then it is marked "Leader" with p-value and expected lift shown. - Given historical comparison, When I select a prior experiment as baseline (auto-suggested by asset/category), Then a comparison table shows deltas vs baseline and a sparkline of historical performance. - Given insufficient data, Then the summary clearly states "Underpowered" and suppresses winner designation.
Activity Audit Trail
- Given any experiment change (create, edit config, traffic split change, start/stop, annotation add/edit/delete, export), Then an audit entry is recorded with UTC timestamp, actor (user id and name), action, and before/after values. - Given I open the Audit tab, Then I can filter entries by action type and date range and see paginated results ordered by newest first. - Given permissions, Then only users with "Editor" or higher can make changes; all users with "Viewer" can read the audit log; unauthorized actions return HTTP 403 and no audit entry is created.
Recommendations & Health Checks
- Given an active experiment, When estimated power for the configured MDE is < 80% based on current sample rate and duration, Then show an "Underpowered" warning with a recommendation to extend duration or increase traffic and an estimated additional sample size. - Given traffic allocation target (e.g., 50/50), When observed traffic share deviates by > 10% absolute for any variant over the last 24 hours or last 5,000 impressions (whichever is larger), Then show an "Uneven Traffic" warning with suggested corrective action. - Given the primary metric shows |lift| < 1% after at least 10,000 impressions, Then surface a "Low Sensitivity" note recommending raising MDE or changing metric. - Given any health check is resolved (conditions no longer met), Then its banner auto-dismisses within 1 hour and the resolution is logged in the audit trail.
Privacy, Consent, and Data Governance
"As a compliance-conscious publisher, I want experiments to respect user consent and privacy laws so that I can run tests without legal risk."
Description

Ensure compliant traffic assignment and tracking by integrating consent management for cookies/identifiers on ClipSpark Share Pages and embeds. Anonymize or pseudonymize user identifiers where required, and respect Do Not Track and regional regulations (e.g., GDPR/CCPA). Provide data retention controls, per-project access permissions, and an opt-out mechanism that still allows non-personalized experiments where feasible.

Acceptance Criteria
Consent-Gated Tracking on Share Pages and Embeds
Given a first-time visitor loads a ClipSpark Share Page or embed, When the page initializes before consent is recorded, Then only essential cookies/storage are used and no requests are sent to analytics, A/B assignment, or attribution endpoints. Given a visitor provides affirmative consent in the banner, When the page continues, Then A/B variant assignment and analytics (impressions, CTR, watch-time) are enabled using a pseudonymous identifier. Given a visitor declines or dismisses consent, When the page continues, Then only essential functionality is active and no tracking or A/B assignment persists across pageviews.
DNT/GPC and Non-Personalized Experiment Fallback
Given the browser sends a Do Not Track (DNT=1) or Global Privacy Control (GPC) signal, When a Share Page or embed loads, Then ClipSpark treats the visitor as opted-out: no non-essential cookies, no persistent identifiers, and no cross-session linkage are created. Given a visitor is opted-out via DNT/GPC or explicit preference, When A/B experiments run, Then variant assignment uses per-page, in-memory randomization without persistence and no per-user metrics are transmitted; only on-page rendering differences occur.
Regional Compliance: GDPR vs CCPA Behavior
Given geolocation resolves to EU/EEA/UK, When explicit consent has not been given, Then tracking and A/B analytics are disabled and no data is transmitted except essential operations; non-personalized rendering may occur without network calls. Given geolocation resolves to EU/EEA/UK and consent is given, When the page continues, Then analytics and A/B operate under a pseudonymous identifier and a consent record with timestamp and region is stored. Given geolocation resolves to California, When the user activates Do Not Sell/Share or a valid GPC signal is present, Then sale/share-restricted processing is disabled, a Do Not Sell/Share link is visible on the Share Page, and only de-identified, aggregate metrics are collected. Given geolocation resolves to other regions, When local regulations require opt-in or opt-out, Then the system applies the corresponding default (opt-in vs opt-out) as configured in regional policy settings.
Identifier Anonymization and Pseudonymization
Given consent has not been granted, When the page assigns any experiment variant, Then no persistent identifier is created and any temporary ID is memory-only and excluded from network payloads. Given consent has been granted, When creating a user identifier, Then the identifier is pseudonymous (random GUID or salted hash), contains no PII, is not exposed in URLs, and is stored only in a first-party context. Given any client or server event includes an identifier, When payload validation runs, Then the identifier cannot be correlated with third-party data by design (no shared keys) and is verified to exclude PII fields (e.g., email, IP, device fingerprint).
Per-Project Data Retention Controls
Given a project owner opens Data Retention settings, When a retention period between 30 and 365 days is saved for raw A/B and analytics events, Then the system schedules deletion accordingly and displays the effective purge date. Given events surpass their retention window, When the daily purge job runs, Then raw events are deleted within 24 hours and aggregated metrics remain intact. Given the owner clicks Purge Now for a project, When confirmed, Then eligible raw data is deleted and an audit entry with actor, timestamp, scope, and result is recorded.
Per-Project Access Permissions for Experiment Data
Given a user role is Viewer or Editor, When accessing experiment analytics, Then only aggregated results (CTR, watch-time, confidence) are visible and raw event exports/endpoints return 403. Given a user role is Analyst, Admin, or Owner, When accessing raw logs or exporting data, Then access is granted for the selected project only and cross-project data is not exposed. Given a public Share Page or embed, When network requests are inspected, Then no per-user identifiers or raw event payloads are exposed; only necessary assets and aggregate endpoints are called.
Consent Change and Revocation Lifecycle
Given a user opens consent settings on a Share Page, When consent preferences are changed or revoked, Then new tracking stops immediately and the preference is persisted. Given consent is revoked and a pseudonymous identifier exists, When the revocation is submitted, Then server-side data linked to that identifier is queued for deletion and purged within 30 days; aggregated, de-identified metrics remain. Given consent is changed from deny to allow, When the page reloads, Then tracking and A/B analytics resume under a new pseudonymous identifier without linking to prior data.

UTM AutoTag

Automatically append clean UTM parameters and campaign IDs per share destination (Slack, Email, X, LinkedIn). Shorten links, prevent duplicates, and sync attribution to GA4, HubSpot, and Salesforce—saving time and delivering trustworthy channel-level insights.

Requirements

Channel-Aware UTM Templates
"As a marketer repurposing clips, I want channel-specific UTM tags to be applied automatically when I share so that I get accurate, comparable attribution across Slack, Email, X, and LinkedIn without manual editing."
Description

Provide per-destination (Slack, Email, X, LinkedIn) UTM templates that auto-populate and append source, medium, campaign, content, and term based on the share context in ClipSpark. Support workspace-level defaults, tokenized variables (e.g., {video_id}, {clip_id}, {creator}, {timestamp}), and fallbacks when a destination lacks a custom template. Include preview before share, consistent parameter ordering, and automatic casing/slug rules to produce clean, GA4-compatible UTMs. Integrate into the share workflow for captions, summaries, and highlight clips so every outbound link is tagged without manual steps.

Acceptance Criteria
Per-Destination Template Selection and Fallback
Given a workspace with custom UTM templates for Slack and X and a workspace default template When a user shares a link to Slack Then the Slack template is applied to compose utm_source, utm_medium, utm_campaign, utm_content, and utm_term And if the template includes {campaign_id}, it resolves to the Slack-specific campaign ID stored for the workspace Given the same workspace When a user shares a link to LinkedIn (no LinkedIn-specific template exists) Then the workspace default template is applied And no manual input is required from the user to append UTMs And exactly one set of utm_* parameters is present on the final URL (no duplicates)
Token Substitution and Safe Encoding
Given a UTM template containing tokens {video_id}, {clip_id}, {creator}, and {timestamp} When a user shares a clip or summary Then each token is replaced with the correct value for the shared asset And {timestamp} resolves to the clip start offset in whole seconds (integer) from the original video And all token values are URL-encoded; reserved characters are percent-encoded once (no double-encoding) And if a token resolves to an empty value, the affected parameter is omitted rather than left blank or with a placeholder And no unresolved {token} text appears in the final URL
Consistent Parameter Ordering, Casing, and Slug Rules
Given a final URL is generated with UTMs When composing the querystring Then parameters are ordered as: utm_source, utm_medium, utm_campaign, utm_content, utm_term, followed by any additional params in alphabetical order And all parameter keys are lowercase And all parameter values are normalized to lowercase, spaces/underscores converted to hyphens, non-alphanumeric characters removed (except hyphen), and multiple separators collapsed to a single hyphen And duplicate keys are deduplicated so only one instance of each UTM key exists And the resulting UTMs conform to GA4 naming (utm_* keys) without extraneous parameters
Preview of Final Tagged URL Before Share
Given the share composer is open with a selected destination When the UTM template or any token value changes Then a preview panel displays the exact final URL (including UTMs) that will be shared And the preview updates within 200 ms of a change And the preview indicates which template is applied (destination-specific or workspace default) And the URL displayed in preview matches byte-for-byte the URL sent upon share
Automatic Link Shortening and Duplicate Prevention
Given a composed long URL with UTMs When the user confirms share Then the system generates (or reuses) a short link for the canonicalized long URL And canonicalization applies the defined ordering and casing/slug rules prior to lookup And if an identical canonical URL already has a short link in the workspace, that short link is reused And only one short link exists per canonical URL per workspace And the short link redirects preserve the full UTM querystring to the destination
Coverage Across Captions, Summaries, and Highlight Clips
Given the user shares captions, summaries, or highlight clips to any supported destination When the share is executed Then every outbound link included in the share payload is tagged using the correct destination template or workspace default And links embedded in message bodies and attachments are tagged And zero untagged links are emitted in the final share payload And no additional manual steps are required to add UTMs
GA4 Compatibility Validation
Given a shared, tagged link is clicked and the visitor lands on a page with GA4 active When the session is inspected via GA4 DebugView or Real-Time Then GA4 attributes the session with the provided utm_source, utm_medium, utm_campaign, utm_content, and utm_term values And the utm_* values contain no spaces (only lowercase letters, numbers, and hyphens per slug rules) And no non-utm parameters conflict with GA4 reserved keys And the UTMs recorded in GA4 match exactly those composed and previewed at share time
Smart Link Shortening & De-duplication
"As a content ops manager, I want ClipSpark to shorten and reuse identical tagged links so that my team avoids duplicate URLs and keeps analytics clean and consistent."
Description

Automatically shorten shared URLs with a first-party short domain or connected shortener, generating a stable short link keyed by the canonical target + UTM set. Before creating a new short link, check for an existing identical target/UTM combination and reuse it to prevent duplicates. Store link metadata (destination, owner, campaign ID) and expose it in the share confirmation UI. Ensure 301 redirects, high availability, and analytics beacon compatibility while preserving all UTM parameters on the final destination.

Acceptance Criteria
Use First-Party Domain for Shortening by Default
Given a first-party short domain is configured and healthy When a user shares a canonical URL with a generated UTM set Then the system creates a short link using the first-party domain And P95 link creation latency is <= 500 ms And if the first-party domain is not configured or unhealthy, a connected shortener is used instead
Reuse Existing Short Link for Identical Target and UTM Set
Given a short link already exists for canonical target A and UTM set U When any user shares canonical target A with the same UTM set U Then the existing short link is returned instead of creating a new one And no additional short-link database record is created And the share confirmation UI labels the link as Reused
Generate Distinct Short Links for Different UTM Sets
Given canonical target A When a user shares A with UTM set U1 and later with UTM set U2 where U1 != U2 Then two different short links are created And each short link is associated with its respective campaign ID and UTM set
Canonicalization and UTM Normalization for De-duplication
Given two long URLs that differ only by UTM parameter order or case, trailing slash, default port, or URL fragment but represent the same canonical target and identical UTM values When they are shortened Then the system treats them as identical for de-duplication And a single short link is reused And if non-UTM query parameters differ, distinct short links are produced And URL fragments are ignored in canonicalization
Metadata Stored and Exposed in Share Confirmation UI
Given a short link is created or reused When the share confirmation UI is displayed Then it shows destination URL, owner, campaign ID, creation timestamp, and new/reused status And the displayed metadata matches the stored values And the metadata is persisted and retrievable via API
301 Redirect With UTM Preservation and Analytics Beacon Compatibility
Given a recipient clicks the short link When the redirect occurs Then the service responds with HTTP 301 And the Location header contains the full destination URL with all UTM parameters intact and unmodified And P95 redirect latency is <= 200 ms And destination-page analytics beacons (e.g., GA4, HubSpot) successfully fire in >= 98% of sampled clicks
High Availability and Concurrency Safety
Given normal production load and peak bursts up to 1000 link generations per minute When multiple concurrent requests attempt to create the same canonical target + UTM short link Then exactly one short link record is created and all callers receive the same short URL And monthly service uptime for link creation and redirect endpoints is >= 99.95% And no data races or duplicate keys are observed in logs or metrics
GA4/HubSpot/Salesforce Attribution Sync
"As a demand gen lead, I want UTM-tagged shares to automatically update GA4, HubSpot, and Salesforce so that I can attribute engagement and pipeline back to specific channels and campaigns without manual import."
Description

Sync share events and UTM attributes to GA4 via Measurement Protocol and to HubSpot and Salesforce via native connectors. Map UTM fields to GA4 event parameters and to CRM campaign/contact properties (e.g., CampaignMember in Salesforce). Use an asynchronous job queue with retries, idempotency keys, and dead-letter handling to ensure reliable delivery. Provide workspace-level mappings, API credential management, and per-destination source/medium defaults. Surface sync status and errors in an activity panel for troubleshooting.

Acceptance Criteria
GA4 Measurement Protocol Event Sync
Given the workspace has valid GA4 measurement_id and api_secret When a user shares a ClipSpark asset via a supported destination with UTM parameters and a campaign ID Then exactly one Measurement Protocol event is sent within 5 seconds of the share timestamp with the event name equal to the configured value (default: "share") And event parameters include the mapped utm_source, utm_medium, utm_campaign, utm_content, utm_term, destination, campaign_id, asset_id, workspace_id, share_id, and timestamp_micros And the GA4 endpoint responds with HTTP 2xx and the request is logged with a correlation ID And the event appears in GA4 DebugView within 2 minutes when debug_mode is enabled for testing
CRM Sync: HubSpot and Salesforce Mapping and Association
Given valid HubSpot and Salesforce connectors and workspace-level field mappings are configured When a share event is processed with a contact identifier per mapping (e.g., email) Then HubSpot mapped Contact properties (utm_source, utm_medium, utm_campaign, utm_content, utm_term, and campaign_id if applicable) are upserted for the identified contact without altering non-mapped properties And if a HubSpot campaign mapping exists, the contact is associated to the specified campaign ID exactly once per share_id And a Salesforce CampaignMember is created or updated for the mapped Campaign and matched Lead/Contact with status equal to the configured default (default: "Sent") And mapped UTM fields are written to the CampaignMember or related fields per the workspace mapping And if no HubSpot/Salesforce person match is found, the job is marked Skipped with reason "No Match"
Asynchronous Job Queue Reliability and Dead-Letter Handling
Given downstream services are healthy When 1000 share events are enqueued within 60 seconds Then at least 99% of jobs complete within 60 seconds end-to-end And transient failures (network errors, HTTP 5xx) are retried up to 5 times with exponential backoff starting at 2s and capped at 2 minutes with jitter And permanent 4xx errors are not retried and are marked Failed with the final response code and message And jobs exceeding max attempts are moved to the Dead-Letter Queue with error context (destination, response code, message, attempt count, last attempt timestamp) And the queue preserves FIFO ordering per share_id
Idempotency and Duplicate Prevention Across Destinations
Given the idempotency key is derived deterministically from workspace_id + destination + asset_id + canonical_url + campaign_id + share_timestamp When the same share event is received or retried multiple times Then exactly one GA4 event is recorded, exactly one HubSpot update is applied, and exactly one Salesforce CampaignMember is created or updated for that idempotency key And subsequent deliveries with the same idempotency key result in no state change and are logged as Duplicate-Skipped And idempotency keys are persisted for at least 30 days to prevent cross-deployment duplicates
Workspace-Level Field Mappings and Per-Destination Defaults
Given an admin configures GA4 event parameter mappings and CRM field mappings at the workspace level When the configuration is saved Then the mappings are validated against allowed target fields and take effect only for new events And per-destination defaults for utm_source and utm_medium are applied when missing from the share And explicit UTM parameters on the share override destination defaults And no duplicate UTM parameters are appended to links and all UTM values are URL-safe and normalized to lowercase
API Credential Management and Rotation
Given a workspace admin adds GA4, HubSpot, and Salesforce credentials When credentials are saved Then each connector is validated with a live test call and credentials are stored encrypted at rest with secrets redacted in logs and UI And OAuth tokens are refreshed automatically before expiry; refresh failures mark jobs as Auth-Error and pause retries until credentials are corrected And rotating credentials (adding new, deactivating old) does not drop or duplicate in-flight jobs And deleting credentials disables new sync attempts for that destination and surfaces clear errors for dependent jobs
Activity Panel: Sync Status, Payloads, and Errors
Given a share event has been processed When a user opens the workspace activity panel Then the panel displays a row per destination (GA4, HubSpot, Salesforce) with status (Queued, In-Flight, Succeeded, Failed, Skipped), first/last attempt timestamps, attempt count, and next retry ETA And users can filter by destination, status, and time range, and search by share_id or idempotency key And request/response payload previews are viewable with credentials redacted and users can copy payload JSON And failures display error codes/messages and correlation IDs, and Dead-Lettered items are labeled with their reason
Campaign ID Generation & Mapping
"As a lifecycle marketer, I want consistent campaign IDs attached to every shared asset so that reporting aligns across channels and CRMs without reconciliation work."
Description

Enable automatic generation and manual entry of campaign IDs that tie ClipSpark assets (videos, clips, summaries) to marketing campaigns. Define naming conventions, date ranges, and ownership; map each share to a campaign ID for consistent cross-channel reporting. Provide lookup and autocomplete of existing campaigns, prevent ID collisions, and allow per-workspace rules that connect campaign IDs to UTM campaign values. Expose campaign ID in the UI and propagate it to short links and downstream attribution syncs.

Acceptance Criteria
Auto-Generation on Share
Given a workspace naming convention rule is configured When a user shares any ClipSpark asset via Slack, Email, X, or LinkedIn Then a campaign ID is auto-generated according to the rule and attached to the share Given no naming rule exists When a user initiates a share Then the system requires selecting or entering a campaign ID before allowing the share to proceed Given an ID is generated When the share completes Then the ID is persisted on the asset-share record and is retrievable via UI and API Given >= 50 concurrent shares When IDs are generated Then 99th percentile generation latency is <= 200 ms
Collision Prevention and Uniqueness
Given any campaign ID exists in the workspace When a new ID (auto or manual) would collide Then creation is blocked and a clear error with the next available suggestion is shown Given two concurrent auto-generations target the same base ID When both requests commit Then only one receives the base ID and the other receives a non-colliding ID; no duplicate IDs exist in the workspace Given an attempt to import IDs in bulk When duplicates are detected Then the import reports the conflicting rows and skips them without creating partial mappings
Manual Entry with Naming Convention Validation
Given a workspace pattern (regex), allowed characters, and length limits When a user manually enters a campaign ID Then client- and server-side validation enforce the rule and display inline errors for violations Given the entered ID is valid and unused When the user saves Then the campaign ID is created and associated with provided metadata (name, owner, date range) Given the entered ID is invalid or already in use When the user saves Then the save is blocked and no partial campaign record is created
Date Range and Ownership Assignment
Given a campaign ID with start and end dates and an owner When a user assigns it to a share whose timestamp is outside the date range Then assignment is blocked with a message indicating the conflict and a link to edit (if permitted) Given the user has Campaign Manager permission When editing a campaign Then they can update date range and owner and changes are audit-logged with actor, timestamp, and previous values Given auto-tagging runs after a campaign’s end date When a share is created Then the system selects the workspace default active campaign or prompts for manual selection
Lookup and Autocomplete of Existing Campaigns
Given a user types at least 2 characters in the campaign field When searching Then the typeahead returns up to 10 matches by ID or name within 200 ms and highlights matched terms Given no campaigns match When searching Then the UI shows “No campaigns found” and, if permitted, a “Create new campaign” action Given keyboard navigation is used When the user presses Arrow keys and Enter Then the highlighted option is selected and the field is populated
Mapping Campaign ID to UTM Campaign per Workspace Rules
Given a workspace mapping rule is defined (e.g., utm_campaign = {campaign_id}) When generating a short link Then utm_campaign is set per rule and sanitized (lowercase, spaces to '-', max 100 chars) Given per-destination overrides exist When sharing to Slack, Email, X, or LinkedIn Then the utm_campaign value reflects the destination-specific mapping Given a destination URL already contains UTM parameters When creating the short link Then duplicate parameters are not added and precedence follows workspace rule order (override > existing > default)
Expose and Propagate Campaign ID to UI, Short Links, and Attribution Syncs
Given a share is created When viewing the asset share details UI Then the campaign ID is visible, copyable, and filterable Given a short link is generated When resolving to the destination URL Then the URL includes the mapped utm_campaign (or cid parameter if configured) carrying the campaign ID Given GA4, HubSpot, and Salesforce integrations are enabled When syncing share events Then the campaign ID is sent to each system’s expected field and a 2xx response is recorded; failures retry 3 times with exponential backoff and are logged for review
UTM Sanitization & Conflict Resolution
"As a social media manager, I want ClipSpark to clean and reconcile UTMs on any link I share so that I avoid broken tags, duplicates, and inconsistent analytics."
Description

Detect existing UTM parameters on pasted or imported URLs and apply workspace policies to merge, override, or preserve them. Canonicalize parameter order, ensure proper URL encoding, normalize case, and strip disallowed or duplicate parameters. Validate against GA4-compatible keys and reserved parameters, and flag conflicts to the user with a clear resolution preview before share. Log all changes for traceability and ensure the resulting URL remains functionally equivalent to the original target.

Acceptance Criteria
Override Policy on Existing UTMs
Given a workspace policy set to Override for destination LinkedIn with defaults utm_source=linkedin, utm_medium=social, utm_campaign=clipspark, utm_id=LK-123 And a pasted URL https://example.com/page?utm_source=twitter&utm_medium=social&utm_campaign=old&id=123 When sanitization runs for destination LinkedIn Then the resulting URL contains utm_source=linkedin, utm_medium=social, utm_campaign=clipspark, utm_id=LK-123 And any other utm_* keys not in the allowed GA4 set are removed And non-UTM parameters (e.g., id=123) are preserved unchanged And no duplicate UTM keys exist
Merge Policy Without Overwriting Conflicts
Given a workspace policy set to Merge for destination Slack with defaults utm_source=slack, utm_medium=share, utm_campaign=clipspark And a pasted URL https://example.com/page?utm_source=partner&utm_content=ctaA When sanitization runs for destination Slack Then the resulting URL keeps existing utm_source=partner and utm_content=ctaA And adds missing defaults utm_medium=share and utm_campaign=clipspark And removes any duplicate UTM keys so each allowed key appears at most once
GA4 Compliance and Reserved Parameter Handling
Given a pasted URL containing utm_source, utm_medium, utm_campaign, utm_content, utm_term, utm_id, utm_extra=bad, gclid=abc123, fbclid=xyz789 When sanitization runs Then only GA4-compatible UTM keys remain: utm_source, utm_medium, utm_campaign, utm_content, utm_term, utm_id And utm_extra is removed with a validation warning recorded And reserved non-UTM parameters (e.g., gclid, fbclid) are preserved unchanged And attempting to introduce non-GA4 UTM keys results in their removal prior to share
Canonicalization, Encoding, and Case Normalization
Given a pasted URL whose query contains mixed-case UTM keys/values, spaces and unicode characters, and duplicate keys When sanitization runs Then all UTM keys are lowercased and UTM values are lowercased And percent-encoding is normalized per RFC 3986 (no double-encoding; spaces encoded as %20) And query parameters are ordered canonically: non-UTM parameters first (original order preserved), followed by UTMs ordered as utm_source, utm_medium, utm_campaign, utm_id, utm_term, utm_content And duplicate occurrences of the same key are collapsed to a single key whose value reflects the active policy (Override or Merge) And the final URL parses successfully as a valid URL
Conflict Resolution Preview Before Share
Given sanitization detects any changes to UTM keys/values or removal of disallowed keys When the user initiates Share Then a preview displays original vs. sanitized URL, the applied policy, and an itemized list of keys added, changed, or removed with reasons And Share proceeds only after the user confirms the preview And on Cancel, the Share is aborted and the original URL remains unchanged And on Confirm, the shared link exactly matches the sanitized preview
Audit Logging and Traceability
Given any sanitization change occurs When the operation completes Then a log entry is created containing timestamp (UTC), user/workspace identifiers, destination channel, original URL, sanitized URL, applied policy, list of keys added/changed/removed, and validation warnings And the log entry has a unique ID and is retrievable in the audit view and via API And logs can be filtered by date range, destination, user, and policy
Functional Equivalence of Target URL
Given an original URL and its sanitized URL When both are requested by the system following redirects up to 5 hops using GET Then the final scheme, host, and path are identical between the two And non-UTM query parameters are identical between the two And the HTTP status code class (2xx/3xx/4xx/5xx) is identical And if a mismatch is detected, the user is warned and Share is blocked unless the user explicitly overrides via confirmation
Admin Policies, Permissions & Audit Trails
"As a workspace admin, I want governance over UTM rules and visibility into changes so that our organization maintains consistent attribution and compliance."
Description

Provide role-based controls for who can create, edit, or override UTM templates and campaign mappings. Allow admins to enforce required parameters, lock templates for regulated workspaces, and define per-destination rules. Maintain immutable audit logs for template changes, link creation, overrides, and sync outcomes, with export capability for compliance. Include environment-aware settings (prod/staging) and data retention policies for link and attribution records.

Acceptance Criteria
Role-Based Template Permissions Enforcement
Given a workspace with roles Admin, Editor, and Viewer defined And UTM templates and campaign mappings exist When a Viewer attempts to create, edit, or delete a UTM template or campaign mapping Then the action is blocked with a 403 error and user-facing message "Insufficient permissions" And an audit log entry is recorded with actor, role, action, resource ID, timestamp, and outcome "denied" Given an Editor attempts to edit an unlocked template within their permitted scope When the edit is submitted Then the change is saved successfully And the audit log records before/after diffs, justification (if provided), and version increment Given an Editor attempts to override a locked template When the override is submitted Then the action is blocked unless a break-glass policy is enabled for their role And if allowed, a mandatory justification and MFA challenge are required And the override is time-bounded (configurable, default 60 minutes) And all events are audited with override window start/end Given an Admin manages role permissions When they update who can create/edit/override templates and mappings Then the system enforces the new policy immediately across UI and API And policy changes are versioned and audited
Required UTM Parameters Enforcement
Given an Admin configures required parameters (e.g., utm_source, utm_medium, campaign_id) for a workspace When a user creates or edits a template or generates a share link without all required parameters Then validation fails with specific missing fields listed And the link/template cannot be saved or shared until requirements are met Given per-destination requirements exist (e.g., LinkedIn requires utm_source=linkedin) When a user sets a conflicting value or leaves it blank Then the system auto-corrects to the enforced value or blocks with a clear error, per policy setting Given a template passes validation When links are generated from it Then 100% of generated links include all required parameters exactly once (no duplicates) And parameters appear in a consistent, canonical order Given a validation failure occurs When the user corrects the inputs Then the system re-validates in real time and permits save/share upon compliance And all validation failures are recorded in audit logs with reasons
Template Locking for Regulated Workspaces
Given a workspace is marked as regulated and an Admin locks a UTM template When any non-Admin attempts to edit, delete, or change mappings on the locked template Then the action is blocked with message "Template is locked by admin policy" And the attempt is logged as denied with actor, resource, and reason Given break-glass is enabled for regulated workspaces When an Admin initiates a temporary unlock or override Then MFA and justification are mandatory And a time-limited window (configurable) is applied and displayed And all changes during the window are grouped under a single override session in the audit log Given the override window expires When further edits are attempted Then they are blocked until a new authorized override is initiated Given a locked template is cloned When the clone is created Then lock state and required parameters are inherited unless explicitly allowed by policy And the inheritance action is audited
Per-Destination Rules Application
Given Admin-configured per-destination rules for Slack, Email, X, and LinkedIn (e.g., utm_source, utm_medium, content, term patterns) When a user generates a share link for each destination Then the correct rule set is applied to the link And forbidden parameters for that destination are omitted And destination-specific defaults are inserted if missing Given a destination rule mandates short-linking When a link is generated Then the URL is shortened via the configured provider And the long URL and short code mapping is stored and auditable Given deduplication rules are enabled (keyed by canonical URL + destination + campaign_id) When a user attempts to generate a link that matches an existing key within the dedupe window Then the existing short link is returned with a notice And a duplicate generation attempt is logged Given conflicting rules are configured When validation runs Then the system highlights conflicts, blocks save until resolved, and records the conflict in the audit log
Immutable Audit Logs and Export
Given audit logging is enabled by default and cannot be disabled by non-Admins When the system records events for template changes, link creation, overrides, permission updates, and attribution sync outcomes (GA4, HubSpot, Salesforce) Then each entry includes timestamp (UTC ISO 8601), actor ID, role, workspace, environment, IP/user agent, action, resource ID/type, before/after diffs (where applicable), and outcome And entries are write-once and immutable (WORM storage or equivalent) And entries are tamper-evident with chained hashes Given an Admin filters the audit log by date range, actor, event type, resource, outcome, and environment When they apply filters Then the results reflect the selected filters within 2 seconds for 10k-entry datasets Given an Admin exports audit logs When exporting to CSV or JSON Then the export respects applied filters and includes a cryptographic checksum of the file And an export event is itself logged with parameters and requester Given retention is configured for audit logs When entries exceed the retention period Then logs are archived or purged according to policy with a tombstone record retained for compliance
Environment-Aware Settings Isolation
Given separate environments (staging, production) are enabled When an Admin configures policies in staging Then those policies do not affect production And the UI and API require explicit environment selection for all policy changes Given a link is generated in staging When the UTM is created Then utm_env=staging (or configured key) is appended And external attribution syncs to GA4/HubSpot/Salesforce are disabled by default in staging or clearly marked as test per policy And the environment is recorded on the link and in the audit log Given a user with production-only permissions is in staging When they attempt a production-only action Then the action is blocked with an environment scope error and audited Given environment-specific API keys exist When sync runs in each environment Then the correct credentials are used and cross-environment leakage is prevented
Data Retention Policies for Links and Attribution Records
Given an Admin sets retention periods for link records and attribution records (e.g., 90/365 days) When records exceed their retention periods Then they are automatically purged or anonymized per policy during a daily scheduled job And purge actions are summarized and logged with counts by record type Given a legal hold is applied to a campaign or workspace When retention jobs run Then records under legal hold are excluded from purge until the hold is released And hold placement/removal is audited with justification Given a user requests GDPR deletion of their personal data in attribution records When the request is approved Then the system deletes or irreversibly anonymizes personal identifiers within 30 days And produces a deletion report export for the request Given retention policies are updated When the new policy is saved Then changes apply prospectively and do not restore already purged data And the policy change is versioned and audited

Quote Overlay

AI lifts the most compelling sentence from the clip and renders it as a dynamic, legible caption on the card. Lock to approved phrasing when needed for compliance—instantly conveying context that stops scrolls and improves click-through.

Requirements

Intelligent Quote Extraction
"As a podcaster, I want the most compelling sentence auto-selected and contextually accurate so that highlight cards immediately convey value."
Description

Leverages ClipSpark’s transcript, speaker diarization, and highlight detection to identify a single, high-impact sentence per clip. Uses language-model ranking with features such as sentiment, novelty, specificity, and call-to-action potential, constrained by brand/compliance rules and target length. Provides confidence scores, context preview, profanity/PII filters, and fallbacks when no candidate meets thresholds. Supports deterministic mode for repeatable outputs and stores the selected quote with precise timestamp alignment to the source media and generated highlight card.

Acceptance Criteria
Selects One High-Impact Sentence Per Clip
Given a processed clip with transcript sentences, speaker diarization, highlight detection results, and configured targetLengthRange and minImpactScore When Intelligent Quote Extraction runs Then it returns exactly one quote that is a single sentence verbatim from the source transcript And the quote length falls within targetLengthRange And the computed impactScore for the quote is >= minImpactScore using sentiment, novelty, specificity, and callToAction features And the selected sentence ranks highest among all candidates by the scoring function
Honors Brand and Compliance Constraints
Given brand/compliance rules including blockedTerms, requiredPhrases, and approvedPhrasing locks are configured When evaluating candidate sentences Then any candidate violating a rule is excluded from selection And if approved phrasing exists for the target segment, the approved phrasing is selected instead of transcript text And if requiredPhrases are configured, the selected quote contains at least one required phrase
Profanity and PII Filtering With Safe Fallback
Given profanity and PII detectors with a configured severityThreshold When all remaining candidates exceed severityThreshold Then no quote is selected and a machine-readable reason code NO_SAFE_CANDIDATE is produced And if an approved fallback phrasing is available, it is returned instead with fallbackUsed=true And no output contains unmasked profanity or PII
Deterministic Mode Produces Repeatable Output
Given deterministicMode=true with a fixed seed and identical inputs When the extraction runs multiple times Then the quote text, startMs, endMs, and impactScore are identical across runs And rerunning in a different environment with the same seed and inputs yields the same outputs
Confidence Scores, Context Preview, and Timestamp Alignment
Given transcript word timings and sentence boundaries with a configured maxTimestampDriftMs and contextWindow When the quote is produced Then startMs and endMs align to the sentence boundaries within maxTimestampDriftMs And a numeric confidenceScore in the range [0,1] is included And a contextPreview is included containing text within the configured contextWindow around the quote
Persists Quote and Associates With Highlight Card
Given a generated highlight cardId and sourceMediaId When a quote is selected Then the system persists the quote text, cardId, sourceMediaId, startMs, endMs, and scores in durable storage And retrieving the highlight card returns the same stored quote and timestamps And rerunning extraction with identical inputs and deterministicMode=true is idempotent and does not create duplicate records
Compliance Phrase Locking
"As a compliance manager, I want overlays restricted to approved phrasing so that published clips meet regulatory requirements."
Description

Enables workspaces to maintain an approved phrase library and mappings per topic or campaign. When enabled, the overlay selects only from approved phrases or substitutes the nearest approved variant, with admin governance, versioned lists, bulk import/export, rule targeting by clip labels, and audit logging. Provides a lock/unlock toggle at the clip level and surfaces policy reasons when substitutions occur. Integrates with Intelligent Quote Extraction to hard-block disallowed terms and with Export to ensure compliant text is burned in.

Acceptance Criteria
Admin Manages Approved Phrase Library and Topic/Campaign Mapping
- Given a workspace admin is authenticated, when they create a new phrase list with unique name and scope (topic/campaign/workspace default), then the list is saved and visible in the library index within 2 seconds. - Given an editor is authenticated, when they attempt to create or edit a phrase list, then access is denied with a permission error, and view-only access is allowed. - Given a phrase is added, when the same exact phrase exists in the scoped list, then the system rejects it with a duplicate message; when it exists in another scope, then both can co-exist. - Given mappings are defined between phrases and topics or campaigns, when a topic or campaign is selected, then only mapped phrases are eligible for selection by the overlay engine. - Given an admin deletes a phrase list, when the list is in use by active rules, then the system blocks deletion and suggests disabling rules first.
Clip-Level Compliance Lock Toggle and Persistence
- Given a new clip is created, when the workspace default is compliance lock enabled, then the clip's lock state defaults to locked; otherwise unlocked. - Given a user with edit rights toggles the compliance lock on a clip, when they save, then the state persists and is reflected in UI, API, and subsequent renders. - Given a clip is locked, when Intelligent Quote Extraction selects a quote, then the overlay engine must restrict to approved phrases only. - Given a clip is unlocked, when a quote is selected, then the overlay may use non-approved phrases unless disallowed terms are present. - Given the lock state changes, when an event occurs, then an audit entry is recorded with user, timestamp, previous/new state, and clip ID.
Approved-Only Selection and Nearest Variant Substitution with Reason
- Given a clip is locked and the AI-selected quote is not in the approved list for its labels, when substitution is enabled, then the system selects the nearest approved variant based on similarity threshold configurable per workspace (default ≥ 0.8 cosine). - Given a substitution occurs, when the overlay renders, then a policy banner or tooltip displays “Substituted to approved phrase” with the originating phrase, selected variant, list version ID, and rule reference. - Given no approved variant meets the similarity threshold, when selection runs, then the system offers the top approved phrase suggestion and flags the overlay as “Needs Approval,” blocking publish/export until resolved or lock is turned off. - Given a user clicks “View Policy,” when a substitution was applied, then the detailed policy reason modal shows the rule match, disallowed terms encountered (if any), and the decision path.
Disallowed Terms Hard Block via Intelligent Quote Extraction
- Given a workspace has disallowed terms configured, when Intelligent Quote Extraction detects any disallowed term in a candidate quote, then the quote is rejected and not passed to overlay rendering. - Given disallowed terms are detected and the clip is locked, when no compliant variant is available, then the overlay is suppressed and a blocking error message is shown with the specific term(s) and policy link. - Given disallowed terms are detected and the clip is unlocked, when a user attempts to publish/export, then the system warns and requires explicit acknowledgement; the disallowed terms are still removed from burned-in text. - Given a disallowed term detection event, when logging occurs, then the audit log records term(s), source timestamp(s), detector version, and user actions taken.
Rule Targeting by Clip Labels with Precedence and Fallback
- Given a clip has labels for topic and campaign, when compliance lock is enabled, then the system applies phrase lists using precedence: clip-specific override > campaign > topic > workspace default. - Given multiple rules match at the same precedence level, when selection occurs, then the rule with the most recent effective date takes priority; ties break by lexicographic rule ID. - Given no rule matches the clip labels, when selection occurs, then the workspace default approved list is used; if none, publish/export is blocked until a rule is assigned or lock is turned off. - Given labels change on a clip, when the overlay is re-generated, then the applied rule and eligible phrases update accordingly and are recorded in audit logs.
Versioned Lists, Bulk Import/Export, and Audit Logging
- Given an admin edits a phrase list, when they save changes, then a new immutable version is created with incremented version number and changelog note. - Given an admin views the list history, when they select a prior version, then they can preview and restore it, creating a new head version; no prior versions are deleted. - Given a CSV or JSON import file with up to 10,000 phrases and metadata (scope, labels, status), when uploaded, then the system validates schema, deduplicates within scope, rejects disallowed terms, and produces a dry-run report before apply. - Given an import is applied, when processing completes, then success/failure counts and rejected rows with reasons are displayed and written to the audit log. - Given an admin exports a phrase list, when they choose a format (CSV/JSON), then the export includes phrases, scopes, mappings, current version ID, and rule associations. - Given any administrative action (create, update, delete, import, restore), when it occurs, then an audit entry captures actor, action, objects, diffs, timestamp, and IP.
Export Enforces Compliant Burn-In
- Given a clip is locked and ready for export, when the export starts, then the burned-in quote overlay text must match the approved phrase and include the phrase list version ID in export metadata. - Given a mismatch between rendered overlay text and the approved phrase, when validation runs pre-export, then the export is blocked with a corrective action message and a link to re-generate overlay. - Given a clip is unlocked, when exporting, then the system allows non-approved quotes but still strips disallowed terms from burned-in text and logs a warning. - Given exports in MP4, MOV, and vertical 9:16 presets, when exporting with lock enabled, then all output variants contain the compliant burned-in text and pass checksum validation of embedded metadata.
Adaptive Overlay Rendering
"As a content creator, I want the quote rendered legibly and dynamically across formats so that it captures attention and remains readable on any device."
Description

Renders the selected quote as an animated, high-contrast overlay optimized for readability across 9:16, 1:1, and 16:9 outputs. Implements responsive typography, auto line-breaking, dynamic text fitting, safe-area awareness, background treatments, entrance/exit animations, and motion-reduced mode. Meets WCAG AA contrast, supports emojis and extended glyph sets, and avoids occluding faces or lower-thirds where possible. The render pipeline outputs frame-accurate overlays for preview and final export with GPU acceleration when available.

Acceptance Criteria
Responsive Typography Across Aspect Ratios
Given a selected quote and a target aspect ratio of 9:16, 1:1, or 16:9 at 720p, 1080p, or 2160p When the overlay is rendered for preview or export Then the text scales responsively to fit within the defined safe area with margins of at least 5% on all sides And the overlay uses no more than 5 lines and no characters are clipped or overflow outside the safe area And automatic scaling ensures the entire quote (up to 220 grapheme clusters) is visible without truncation And the overlay’s bounding box occupies no more than 40% of the frame height And line length is balanced to avoid single-word orphan lines where language permits
WCAG AA Contrast and Background Treatment
Given any frame under the text overlay region When measuring contrast between rendered text and its effective background (including shadows/outline/plates/blur) Then the contrast ratio is at least 4.5:1 for normal text or 3:1 for large text (≥24 px at 1080p, scaled proportionally) And if the live background would drop contrast below thresholds, a background treatment is auto-applied within 1 frame to restore compliance And contrast remains at or above threshold for 100% of frames while the overlay is visible And transitions between treatments do not produce visible flicker or color pumping
Dynamic Fit and Auto Line-Breaking
Given a quote containing spaces, punctuation, emojis, and multi-language text up to 220 grapheme clusters When the overlay computes layout Then automatic line-breaking occurs at word boundaries (or grapheme cluster boundaries for CJK/emoji) without splitting grapheme clusters And text fits within the safe area with zero truncation and zero horizontal scrolling And minimum line height is at least 1.2x the computed font size to prevent collisions And kerning and tracking remain within font defaults (±2% adjustment max) to achieve fit
Face and Lower-Third Avoidance
Given detected face bounding boxes and any existing lower-third/graphic regions for the clip When positioning the quote overlay Then the overlay’s bounding box overlaps less than 1% area with any detected face or lower-third in at least 95% of frames where the overlay is visible And the engine may reposition (top/middle/bottom) and scale text down by up to 15% to maintain the overlap threshold And if overlap exceeds 5% in any frame after adjustments, the system flags the render with an “overlay may occlude subject” warning
Entrance/Exit Animations and Reduced Motion
Given standard motion settings When the overlay enters and exits Then it uses GPU-composited transform/opacity animations at 60 fps with durations between 250 ms and 400 ms using ease-in-out timing, without layout thrashing And during preview playback, dropped frames while the overlay animates are under 1% of frames And Given the user or OS indicates prefers-reduced-motion or animations are disabled When rendering the overlay Then entrance/exit effects are replaced with a non-moving fade of 100–150 ms duration and no motion is applied
Unicode, Emoji, and Extended Glyph Support
Given quotes containing Unicode including RTL scripts (Arabic/Hebrew), CJK, combining marks/diacritics, ligatures, and emojis (including ZWJ and skin-tone variants) When the overlay text is rendered Then BiDi ordering and shaping follow the Unicode algorithm and script-specific shaping rules And no missing-glyph boxes appear; a fallback font stack renders unsupported glyphs seamlessly And grapheme clusters are not split across lines; emojis and ZWJ sequences remain intact And baseline alignment for emoji and text is consistent within ±2 px at 1080p (scaled proportionally) And the rendered text matches the provided quote string exactly (no smart substitution or autocorrection), preserving punctuation and casing
Frame-Accurate Preview and Export with GPU Acceleration
Given overlay start and end timestamps aligned to the source video frame rate When previewing and exporting to H.264 and ProRes at 24, 30, or 60 fps Then the overlay appears from start frame N through end frame M inclusive and is absent outside that range with 0-frame drift And export timecodes match preview timing within ±1 ms And when a compatible GPU is available, the renderer uses GPU acceleration for text rasterization/compositing (as indicated by performance logs/metrics), with a CPU fallback producing pixel-identical results
Brand Styling Presets
"As a brand marketer, I want to apply branded styles to overlays so that clips are on-brand without manual design work."
Description

Provides reusable style presets per workspace including fonts, weights, color palettes, text effects, logo lockups, and animation profiles. Users can choose a preset when creating a card or set a default per project. Supports font uploads with fallbacks, per-language typographic rules, and tokenized styles to ensure consistency. Presets apply non-destructively so quotes can be re-rendered in different brand looks without re-editing, integrating with the renderer and export pipeline for consistent visuals.

Acceptance Criteria
Workspace Admin Creates Valid Brand Preset
Given I am a Workspace Admin, When I create a Brand Preset with a unique name, selected fonts and weights, a color palette (minimum primary and contrast), text effects parameters, a logo lockup asset, and an animation profile, Then the preset saves successfully and is available to all workspace members. Given any required field is missing or an uploaded asset is of an unsupported type (e.g., non-font for font, non-image for logo), When I attempt to save, Then validation errors are shown inline and the preset is not saved. Given caption foreground and background colors are set, When their contrast ratio is below 4.5:1, Then the system blocks save and requires explicit user confirmation to proceed; if confirmed, the preset saves with a recorded warning.
Project Default Preset Application and Override
Given a Project has Default Brand Preset A, When a user creates a new Quote Card, Then Preset A is applied automatically to the card. Given a Quote Card with Preset A, When the user selects Preset B and saves, Then Preset B is applied and persists for that card only. Given existing cards in a project, When the project default is changed from Preset A to Preset C, Then existing cards retain their current preset and only new cards use Preset C.
Non-Destructive Re-Render on Preset Update
Given multiple Quote Cards use Brand Preset A, When Preset A tokens (fonts, colors, text effects, logo, animation profile) are updated and saved, Then each affected card preview re-renders to reflect the new style without altering quote text, captions’ timestamps, trims, or compliance locks. Given a previously exported video for a card using Preset A, When Preset A is updated, Then the existing exported file remains unchanged until a new export is initiated, and the new export uses the updated preset. Given a card uses Preset A, When the user switches the card to Preset B, Then only visual styling changes; content and timing remain unchanged.
Font Uploads, Fallbacks, and Language-Specific Typography
Given I upload a custom font file (TTF, OTF, WOFF, or WOFF2) to a preset, When the upload completes, Then the font is validated, listed with available weights, and unusable formats are rejected with an error. Given caption text includes characters unsupported by the selected font, When rendering preview or export, Then the configured fallback font with at least 95% glyph coverage for the text’s script is used automatically without line layout shifts greater than 1px per line. Given the detected script is right-to-left (e.g., Arabic or Hebrew), When rendering the Quote Overlay, Then RTL direction, ligatures, and per-language line-breaking rules are applied; for CJK scripts, Then preset-defined line-height and CJK line-breaking rules are applied. Given an uploaded font is unavailable at render time, When rendering occurs, Then the fallback font is applied and a non-blocking warning is displayed and logged.
Renderer–Export Visual Parity Across Formats and Sizes
Given a Quote Card preview styled by a Brand Preset, When exporting to MP4 and WebM at 1080x1920, 1080x1080, and 1920x1080, Then exported visuals (fonts, colors, text effects, logo position, and animation timing) match the preview with position variance ≤1px and animation timing variance ≤16ms per keyframe. Given color-managed rendering, When exporting, Then color appearance in the export matches the preview with deltaE ≤ 2 and vector logos are rasterized at ≥2x target resolution to remain crisp. Given different aspect ratios, When exporting, Then preset-defined anchoring and scaling maintain relative positions of text and logo consistently across sizes.
Preset Access Control, Usage Protection, and Audit
Given workspace roles, When a non-Admin user attempts to create, edit, or delete a Brand Preset, Then the action is blocked; when an Admin performs the action, Then it succeeds. Given a Brand Preset is in use by any card or set as a project default, When an Admin attempts to delete it, Then deletion is blocked and the system requires reassignment of affected entities to another preset before deletion can proceed. Given any change to a Brand Preset, When it is saved, Then an audit log entry records actor, timestamp, changed fields, and affected projects/cards.
Timing and Placement Controls
"As an editor, I want precise control over when and where the quote appears so that it aligns with the moment and avoids obscuring key visuals."
Description

Auto-synchronizes overlay start and end with the quoted sentence timestamps and provides manual nudge controls and duration caps. Offers vertical and horizontal placement presets, per-platform safe-zone guides, and smart placement to avoid captions, watermarks, or detected faces. Includes pin-to-subject using face/object tracking and configurable margins/padding. Timeline UI displays overlay bars aligned with waveform and transcript for precise adjustments.

Acceptance Criteria
Auto-Sync to Quote Timestamps
Given a clip with an extracted quoted sentence having start/end timestamps Tstart and Tend, When the Quote Overlay is generated, Then the overlay start equals Tstart within ±100ms and end equals Tend within ±100ms. Given the user trims the quoted sentence boundaries in the transcript, When changes are saved, Then the overlay start/end update within 200ms UI response and remain within ±100ms of the new boundaries. Given the project is exported, When reviewing the rendered video at 30fps, Then the overlay in the output appears within ±1 frame of the in-app overlay timing for both start and end.
Manual Nudge and Duration Caps
Given an overlay is selected, When the user nudges the start or end using nudge controls, Then its time shifts by the configured step size (default 50ms) per action. Given an overlay is nudged repeatedly, When its duration would exceed the max cap (default 5s, configurable), Then the end time is clamped to the cap and the UI indicates the cap was reached. Given an overlay is nudged, When the operation would invert start after end or reduce duration below 0.5s, Then the action is blocked and a non-intrusive message explains the constraint.
Placement Presets and Safe-Zone Guides
Given a platform preset is selected (e.g., TikTok, YouTube Shorts, Instagram, LinkedIn), When the canvas loads, Then platform-specific safe-zone guides are displayed with correct dimensions per config. Given a vertical/horizontal placement preset is applied (Top/Middle/Bottom and Left/Center/Right), When confirmed, Then the overlay snaps to the corresponding grid position inside the safe zone with default margins applied. Given a platform preset is active, When previewing or exporting, Then the overlay’s bounding box remains fully inside the platform safe zone for its entire duration.
Smart Placement Collision Avoidance
Given detected regions for captions, watermarks, and faces are available for the overlay’s time range, When smart placement is enabled, Then the overlay is positioned so its bounding box does not intersect any detected region plus a 12px padding. Given no collision-free position exists, When placement is computed, Then the system selects the position with minimum overlap and displays a collision warning to the user. Given a 1080p clip, When computing smart placement for a single overlay frame window, Then the decision completes within 100ms on a standard baseline machine.
Pin-to-Subject Using Face/Object Tracking
Given the user enables Pin-to-Subject and selects a face/object, When the clip plays, Then the overlay anchor follows the subject with smoothing while staying inside the safe zone and honoring margins. Given tracking is active, When measuring across the overlay duration, Then median anchor error is ≤20px and no more than 2 consecutive seconds exceed 40px error. Given the subject is lost for more than 500ms, When tracking fails, Then the overlay holds the last valid position and a non-blocking lost-tracking indicator appears; if the subject is reacquired, tracking resumes automatically.
Configurable Margins and Padding
Given the user edits margins and inner padding (per-side) in pixels or percent, When applied, Then the overlay updates immediately and the values persist for the project and per selected preset. Given margins are set, When any placement mode (presets, smart placement, pin-to-subject) is used, Then the overlay remains fully inside the safe zone minus configured margins for its entire duration. Given user input is out of bounds, When margins/padding exceed limits (min 0, max 10% per side), Then the input is rejected with an inline error explaining allowed ranges.
Timeline UI Alignment with Waveform and Transcript
Given a clip with waveform and transcript, When viewing the timeline, Then overlay bars appear at correct timings aligned with the waveform and corresponding transcript sentences. Given the user drags an overlay bar edge or body, When moving, Then it snaps to transcript sentence boundaries and 0.1s increments with a 60ms snap tolerance. Given the user hovers an overlay bar, When tooltips appear, Then they show start time, end time, and duration; updates to timing reflect in the playhead and transcript highlight with <100ms latency; zooming preserves timing accuracy within 1% scale error.
Platform-Optimized Export
"As a social media manager, I want exports optimized for each platform so that engagement and click-through improve without extra editing."
Description

Generates final media with the quote burned in or as an attached subtitle track, optimized for TikTok, Reels, Shorts, LinkedIn, X, and YouTube. Applies aspect-specific typography, safe-area offsets, and encoding settings that preserve text sharpness. Produces presets aligned with platform limits for duration, file size, and codecs, and names files for easy publishing. Integrates with scheduling/publishing modules when available and preserves metadata linking back to the source clip and quote.

Acceptance Criteria
Export Mode Selection: Burn-in vs Subtitle Track
Given a selected platform preset and a clip with a Quote Overlay When the user selects Export Mode = Burn-in and starts export Then the exported file contains the quote text composited on-video for the intended time range, with no separate subtitle track present Given a selected platform preset that supports external subtitles and a clip with a Quote Overlay When the user selects Export Mode = Subtitle track and starts export Then the exported MP4 includes a single text subtitle stream with timestamps matching the quote time range, and no burned-in quote text appears on the video Given a selected platform preset that does not support external subtitles When the user opens the export dialog Then the Subtitle track option is disabled and Burn-in is pre-selected Given Export Mode = Subtitle track When export completes Then companion .srt and .vtt files are generated with the same basename as the video
Aspect Ratio, Typography, and Safe-Area Compliance
Given any platform preset When export runs Then the output frame size and pixel aspect ratio match the preset definition and padding/cropping strategy Given preset typography tokens When rendering the quote overlay Then font family, weight, size, line height, color, and stroke/shadow are applied per preset within ±1px/±1% tolerance Given a preset with safe-area insets When rendering any frame with overlay Then the overlay bounding box remains fully inside the safe-area on all frames Given multi-line quotes When rendered Then line breaks and text wrapping occur without clipping, truncation, or overflow outside the safe-area
Encoding Targets Preserve Text Sharpness
Given a platform preset with encoding settings When export runs Then the codec, profile/level, pixel format, keyframe interval, and target bitrate/CRF match the preset Given exported video with burned-in text When evaluated by automated OCR at 100% scale over 10 evenly spaced frames containing the overlay Then average character recognition accuracy is >= 98% Given any exported video When measured for contrast between overlay text and its background Then contrast ratio meets WCAG AA (>= 4.5:1) for normal text
Platform Limit Validation and Auto-Remediation
Given a selected platform preset and a clip within all configured limits (duration, dimensions, codec, max file size) When validating pre-export Then no blocking warnings are shown and export proceeds Given a clip exceeding the platform's max duration When validating pre-export Then the user is prompted to auto-trim to the max duration or cancel; choosing auto-trim produces an export within limits Given an estimated file size exceeding the platform limit based on current settings When validating pre-export Then the system offers to adjust bitrate to fit within the limit and displays the new estimated size before continuing Given constraints cannot be met simultaneously (e.g., minimum quality threshold would be violated) When validating pre-export Then export is blocked with a clear error explaining which limit(s) cannot be satisfied
File Naming for Easy Publishing
Given a selected platform preset and export When the file is generated Then the filename follows {projectOrClipSlug}_{platformCode}_{aspect}_{duration}_{YYYYMMDD}_{seq}.{ext} Given any filename generated When validated Then it contains only filesystem-safe characters, is <= 120 characters, and is unique within the destination folder Given a batch export When multiple files are generated for the same clip across presets Then each filename differs by platformCode and/or aspect and increments {seq} as needed
Scheduling/Publishing Integration Handoff
Given a configured publishing connector for the selected platform When export completes Then the asset and metadata are enqueued to the scheduler, creating a draft/scheduled post with a reference to exportId Given no connector is configured When viewing the export confirmation Then Publish/Schedule actions are hidden or disabled and a Download action is available Given a handoff failure from export to scheduler When it occurs Then the user is notified with error details and a Retry action, and the failure is logged with a correlationId
Metadata Preservation and Traceability
Given any export When the file is generated Then embedded metadata includes source_clip_id, quote_id, quote_text, source_url, quote_start_ms, quote_end_ms, export_preset_id via MP4 udta/XMP tags Given a platform known to strip metadata When export runs Then a sidecar JSON file with the same basename stores the same keys and is placed alongside the video Given an exported file or sidecar re-imported into ClipSpark When the system scans metadata Then it reinstates linkage to the original clip and quote, or flags missing references clearly Given Export Mode = Subtitle track When generating .srt/.vtt Then the first comment line encodes quote_id and source_clip_id for traceability
Review and Approval Workflow
"As a producer, I want to review and approve the quote overlays before publishing so that quality and messaging are consistent."
Description

Adds a human-in-the-loop gate for quote overlays. Editors can edit the selected sentence, preview renders, see diffs against the AI pick, and request changes. Roles and permissions restrict who can approve or lock overlays, with batch review, status badges, and activity logs. When compliance lock is required, publishing and export are blocked until approval. All changes are versioned with restore capability.

Acceptance Criteria
Editor Reviews and Edits AI-Selected Quote Overlay
Given a clip with an AI-selected quote overlay and a user with the Editor role When the editor opens the overlay for review Then the AI-selected sentence is displayed in a read-only reference panel And an editable field is prefilled with the AI-selected sentence And a side-by-side diff view highlights insertions in green and deletions in red at word-level between the edit and the AI pick And the editor can Save Draft, which persists the edited text and updates last-modified metadata And navigating away with unsaved changes prompts a confirmation modal to Save, Discard, or Cancel
Overlay Render Preview Matches Final Output
Given an overlay with edited text When the editor clicks Preview Then the preview renders the overlay with the exact text and line breaks currently in the editor And the overlay position, font family, size, weight, and color match the exported clip within 1 px/pt tolerance And the animation timing of the overlay in preview matches the export within 100 ms And exporting the clip produces an overlay visually identical to the preview under the defined tolerances
Approver Approves or Requests Changes to Overlay
Given an overlay in In Review state and a user with the Approver role When the approver clicks Approve Then the overlay status updates to Approved And if the approver enables Compliance Lock, the overlay status updates to Locked and the edited text becomes read-only for non-Approver roles And the approval event records approver, timestamp, and version ID When the approver clicks Request Changes and enters a comment Then the overlay status updates to Changes Requested and the comment is visible to Editors And users without the Approver permission cannot access Approve, Lock, or Unlock actions and see a permissions error if invoked via API And status badges in UI reflect Draft, In Review, Changes Requested, Approved, or Locked states accordingly
Compliance Lock Blocks Publishing and Export Until Approval
Given a project with Compliance Lock Required enabled and an overlay not in Locked status When any user attempts to Publish or Export the clip Then the action is blocked with the message "Compliance approval required before publishing or export" And the Publish and Export controls are disabled until at least one Locked overlay is present for the clip And once the overlay is Locked by an Approver, Publish and Export become enabled and proceed successfully
Batch Review and Bulk Actions on Overlays
Given a list view with multiple overlays in In Review state and a user with the Approver role When the approver selects two or more overlays and chooses Approve Then all selected overlays update to Approved (or Locked if Lock on Approve is selected) And a summary toast shows counts of successes and failures And failures report item-specific error reasons and are not approved When the approver selects overlays and chooses Request Changes with a comment Then all selected overlays update to Changes Requested and the comment is attached per item
Version History, Diff, and Restore
Given an overlay with multiple saved revisions When a user opens Version History Then each version lists author, timestamp, and change summary And the user can select any two versions to view a side-by-side diff highlighting insertions and deletions And the user can restore any previous version, creating a new head version without deleting history And restore is blocked for Locked overlays unless performed by an Approver, in which case the overlay reverts to Draft or In Review per policy
Activity Log and Audit Trail
Given activity logging is enabled When users create, edit, submit for review, approve, request changes, lock or unlock, restore, publish, or attempt to export overlays Then an activity log entry records actor, role, timestamp, action, item ID, and before/after snapshot or diff where applicable And authorized users can filter the activity log by action, actor, date range, and item ID And activity log entries are immutable and each includes a unique identifier for audit

Embed Cards

One-line embeds for websites, blogs, Notion, and LMS that are responsive, lightweight, and privacy-first. Support SSO-gated playback and watermarking via ClipGuard—making it effortless to distribute cards anywhere without file exports.

Requirements

One-line Responsive Embed
"As a creator, I want to paste a single embed code that just works across my website and tools so that I can publish videos quickly without manual styling or custom code."
Description

Provide a single-line embed snippet that renders a responsive, mobile-first ClipSpark card with video playback, timestamped captions, key-moment highlights, and summary preview. The embed auto-detects container width, supports aspect-ratio responsive sizing, and lazy-loads assets to minimize initial page weight. It auto-adapts to light/dark themes, supports right-to-left locales, and exposes configuration via data-* attributes (e.g., start time, autoplay, controls, theme). The snippet works in common CMS/blog platforms without custom scripting and includes graceful degradation for environments that restrict iframes or external scripts. Copy/paste UX in ClipSpark generates the snippet with pre-signed parameters, ensuring instant, accurate embedding with minimal setup.

Acceptance Criteria
Responsive Rendering With Auto Sizing
Given a host page with containers of widths 320px, 768px, and 1200px When the one-line embed snippet is pasted and the page is loaded Then the card renders without horizontal scroll, scales to the container width, and maintains a 16:9 aspect ratio by default across all breakpoints Given data-aspect-ratio="1:1" or data-aspect-ratio="4:5" When the embed renders at any viewport width Then the video area maintains the specified aspect ratio with no visual distortion and no CLS > 0.02 Given the device orientation changes from portrait to landscape When the embed has already rendered Then the card recalculates layout within 200ms and preserves the configured aspect ratio
Lazy Loading and Initial Page Weight
Given the embed is placed below the initial viewport fold When the page first loads Then no video/caption/highlight media requests are made until the card is within 200px of the viewport edge, and at most one lightweight bootstrap request (<35KB gzipped) is made Given the card intersects the viewport by 1px When lazy-load is triggered Then video poster, captions, and highlight data load and render within 500ms on a 4G network, and playback becomes available without blocking main thread > 100ms Given the browser does not support IntersectionObserver When the user clicks the placeholder Then the embed initializes and loads required assets with equivalent behavior and no console errors
Playback With Captions, Highlights, and Summary Preview
Given a valid videoId in the snippet When the user presses Play Then playback starts successfully, and timestamped captions are available and synchronized within ±100ms of spoken audio Given highlight markers are present on the timeline When the user clicks a highlight marker Then playback seeks to the corresponding timestamp and begins playing within 200ms Given a summary preview is available When the user expands or collapses the summary Then the summary toggles without affecting playback, and the toggle is operable via keyboard (Enter/Space) and exposed with aria-controls/aria-expanded
Theme Auto-Adaptation and RTL Support
Given the host page prefers-color-scheme is dark OR data-theme="dark" When the embed initializes Then the card uses the dark theme with minimum WCAG AA contrast for text and controls; switching to light updates styles within 300ms without reload Given the host page sets dir="rtl" or data-rtl="true" When the embed renders Then layout mirrors appropriately: scrubber progresses right-to-left, captions align to the right, timestamps adapt formatting, and keyboard navigation order remains logical
Configuration via data-* Attributes
Given data-start="90" When the user presses Play Then playback begins at 00:01:30 ±1s Given data-autoplay="true" When the embed initializes in a muted-autoplay-allowed environment Then playback auto-starts muted with visible unmute control; in disallowed environments, the card shows a prominent Play button without throwing errors Given data-controls="minimal" OR data-controls="none" When the card renders Then the control set matches the requested mode, and tab order excludes hidden controls Given data-theme="auto|light|dark" When the attribute is changed and the embed re-initializes Then the card applies the specified theme consistently across all UI elements
One-Line Compatibility Across Common CMS/LMS
Given the one-line embed is pasted into WordPress (Classic and Block Editor), Notion, Ghost, Webflow, Squarespace, and Canvas LMS rich text areas When the content is published Then the card renders without requiring custom scripting; if a platform blocks iframes/scripts, a fallback clickable thumbnail and title link are shown instead Given a restrictive Content Security Policy blocks external scripts When the page loads Then the embed falls back gracefully without mixed-content or CSP violations, and a user can still reach the content via an accessible link
Pre-Signed Parameters and Tamper Resistance
Given the snippet includes pre-signed parameters with an expiration time When the token is valid Then the embed loads and plays content without additional user configuration Given a client modifies any protected parameter (e.g., videoId, start time beyond allowed) or the token is expired When the embed initializes Then playback is denied, a non-identifying friendly error is displayed, and no sensitive data is exposed in the DOM or network responses; small clock skew (±5 minutes) is tolerated
Lightweight Bundle & Performance Budget
"As a site owner, I want an ultra-light embed that doesn’t slow my pages so that my SEO and user experience remain high-quality."
Description

Enforce a strict performance budget for the embed (<=60KB min+gz JS, <=8KB CSS, zero blocking fonts), with lazy-loading of the player and captions only on interaction or when in viewport. Use HTTP/2 push hints/preconnect, CDN edge caching, and differential builds for modern browsers. No third-party trackers; only privacy-safe, first-party, aggregate metrics when enabled. Optimize for Core Web Vitals: LCP <=2.5s on 4G, CLS <0.05, TBT minimal via idle initialization. Provide a build-time size report and runtime feature flags to disable non-essential UI to meet budget on constrained pages.

Acceptance Criteria
Bundle Size Budget Enforcement
Given a production build of the ClipSpark Embed Card When the embed JavaScript and CSS bundles are generated Then the total minified+gzipped JavaScript for the embed runtime is <= 60KB And the total minified+gzipped CSS is <= 8KB And no webfont files are referenced or requested by default (zero blocking fonts) And a build-time size report artifact is produced listing per-chunk sizes and totals And the CI build fails if any budget threshold is exceeded (JS, CSS, or fonts present) And source maps and test-only code are excluded from budget calculations
Lazy Load Player and Captions
Given a page with one or more Embed Cards inserted When an embed remains outside the viewport and receives no user interaction Then no network requests for the video player, media, or caption files are made And only the lightweight shell script and minimal CSS are loaded When an embed enters the viewport (>= 1px intersection) or the user interacts (e.g., click/tap) Then the player module and required caption resources are fetched and initialized And on browsers without IntersectionObserver support, the player loads only upon user interaction And preloaded/Prefetched assets (if any) never block first render
Core Web Vitals on 4G
Given a test page with a single above-the-fold Embed Card When measured on a mid-tier device under simulated 4G/Slow 4G (Lighthouse throttling) with a cold cache Then Largest Contentful Paint (LCP) for the page is <= 2.5s And Cumulative Layout Shift (CLS) attributable to the embed is < 0.05 And Total Blocking Time (TBT) during initial load attributable to the embed is <= 150ms And heavy initialization work for the embed occurs in idle callbacks or after first interaction
Network Hints and Edge Caching
Given the embed assets are served via CDN When the embed script is requested Then response headers include Link rel=preconnect for the CDN origin (with crossorigin where applicable) And preload or modulepreload hints are present only for critical assets and do not block first paint And static assets have content-hashed filenames and Cache-Control: public, max-age=31536000, immutable And CDN configuration yields a >= 95% edge hit ratio under synthetic load for repeated requests And origin does not set cookies on static asset responses
Differential Builds for Modern Browsers
Given a modern browser that supports ES modules When loading the embed Then the module build is served (type="module") and the legacy build is not downloaded And the module build minified+gzipped JS remains <= 60KB and CSS <= 8KB Given a legacy browser without module support When loading the embed Then the nomodule build is served and functions equivalently And the nomodule build also meets the JS <= 60KB and CSS <= 8KB budgets And selection between builds does not rely on user-agent sniffing
Privacy-Safe Metrics (Opt-in Only)
Given telemetry is disabled by default When an embed is loaded and used Then no third-party trackers are requested and no analytics requests are sent When telemetry is explicitly enabled via configuration Then only aggregate, first-party events are sent (e.g., load, play, pause) without PII or user identifiers And the system honors Do Not Track (DNT) by suppressing metrics And metrics requests are batched and queued to avoid impacting TBT and LCP And payloads are sent to a first-party endpoint only
Runtime Feature Flags for Budget Control
Given a page specifies runtime flags to disable non-essential UI components When the embed initializes Then code and styles for disabled components are not requested or executed (no network fetches for those modules) And the embed renders core playback controls without visual regressions And enabling a disabled component at runtime results in a deferred, on-demand load only after user action And with select features disabled, the loaded JS and CSS sizes reported at runtime decrease relative to the default configuration
SSO-Gated Playback (OIDC/SAML)
"As an IT admin, I want embedded videos to require our company SSO so that only authorized employees can view protected content anywhere it’s embedded."
Description

Enable optional authentication gates on embeds using enterprise SSO (OIDC/OAuth2, SAML 2.0). Support token exchange via signed, short-lived embed tokens, with silent SSO check using postMessage to a first-party domain and fallback interactive login (popup/redirect) when required. Respect organization policies (domain restriction, group membership, IP allowlists). Expose a simple configuration toggle in ClipSpark to require SSO for specific assets/collections. Ensure embeddability within LMS and corporate portals where third-party cookies are blocked by using token-in-URL (one-time), top-window assisted auth, or LTI where applicable. Provide clear UI states: locked preview, progress spinner, and error messaging for unauthorized users.

Acceptance Criteria
Toggle SSO Requirement per Asset/Collection
Given I am an org admin in ClipSpark with Manage Access permission When I set "Require SSO" to On for Asset A Then new and existing embeds of Asset A require authentication before playback And when set to Off, embeds allow playback without SSO within 60 seconds And when enabled at Collection C level, all child assets are gated within 60 seconds And the change is persisted, auditable, and reflected in the embed snippet as data-require-sso=true
Silent SSO Check via postMessage to First-Party Domain
Given the embed loads where the user may have an active IdP session When the embed performs a silent SSO check via postMessage with a first-party auth iframe Then a definitive result is received within 1500 ms and, if authenticated, playback can start without a popup And the check succeeds without third-party cookies and validates target origin strictly And if no active session exists, the result is auth_required and no PII is exposed
Interactive Login Fallback (Popup or Top-Window Redirect)
Given the silent SSO check returns auth_required When popups are permitted, a centered popup initiates the configured IdP (OIDC or SAML) login within 500 ms Then upon successful login, the embed receives a token and can auto-play within 1 second (subject to browser autoplay policies) And if popups are blocked, a top-window redirect flow completes login and returns to the original URL with state restored And if the user cancels login, the embed remains locked and offers a retry CTA
Signed Short-Lived Embed Token Exchange
Given the user is authenticated via OIDC or SAML When the embed requests an access token Then the token is a JWT signed with RS256 or ES256 and includes iss, sub, aud=ClipSpark-Embed, iat, exp<=300s, and jti And jti is enforced for one-time use; any replay attempt returns 401 And up to ±60s clock skew is accepted; expired tokens return 401 with token_expired And subject and group claims are mapped consistently across OIDC and SAML logins
Organization Policy Enforcement (Domain, Group, IP)
Given org policies require email domain example.com, group Course-101, and IP range 203.0.113.0/24 When an authenticated user attempts playback Then access is granted only if email domain, group membership, and IP checks all pass And any failed check denies playback with HTTP 403 and code E_POLICY_DENIED and displays a friendly message And an audit log entry records the decision and policy reasons without exposing sensitive PII
LMS/Portal Embeds with Third-Party Cookies Blocked
Given the embed is loaded inside an LMS or corporate portal iframe with third-party cookies blocked When a one-time token-in-URL is provided Then playback succeeds once and subsequent loads with the same token return 401 with token_consumed And if no token is provided, the embed uses top-window assisted auth and receives credentials via postMessage within 5 seconds of login And if LTI 1.3 is configured and a valid launch is detected, playback initiates without additional login
Locked, Loading, and Error UI States
Given an unauthenticated user views a gated embed Then a locked preview shows a blurred thumbnail, lock icon, and a Sign in to view button When authentication or token exchange is in progress Then a progress spinner is shown; if no result after 15 seconds, a retry prompt is displayed When authorization fails Then an error state shows You don’t have access with a retry Sign in CTA; all states meet WCAG 2.1 AA for contrast and keyboard access
ClipGuard Dynamic Watermarking
"As a content owner, I want dynamic watermarks on embedded videos so that I can discourage leaks and trace misuse if recording is shared."
Description

Render dynamic, tamper-resistant watermarks in the embedded player to deter unauthorized redistribution. Overlays include viewer identity (name/email or SSO ID), timestamp, and organization name with moving opacity, diagonal tiling, and session-based jitter to resist cropping and static removal. Watermarks respect playback quality changes and full-screen mode, and can be toggled or customized per asset or policy (e.g., only on external domains). Ensure negligible performance impact via GPU-accelerated rendering and efficient canvas/SVG techniques. Watermark configuration is stored in ClipSpark and enforced at playback via signed parameters to prevent user-side removal.

Acceptance Criteria
Watermark Content: Viewer Identity, Timestamp, and Organization Overlay
Given an embedded ClipSpark player with ClipGuard watermarking enabled and a resolved viewer identity and organization When playback starts or resumes Then the overlay renders within 500 ms and remains visible for the entire playback duration And the overlay text includes the viewer display name if available else the email else the SSO subject ID, and the organization display name And the overlay includes a wall-clock timestamp updated at least once per second and never lagging by more than 1 second And the overlay text updates within 3 seconds if the viewer identity changes during the session (e.g., SSO refresh)
Anti-Tamper Dynamics: Diagonal Tiling, Moving Opacity, and Session Jitter
Given watermarking is enabled When the video is playing in the embed Then watermark strings tile diagonally across the visible frame at an angle between 30° and 45° And tile density scales with resolution such that at 1080p at least one watermark substring is visible within any 300×300 px region And overlay opacity oscillates between 8% and 18% with a cycle period between 2 s and 6 s And a session-specific jitter seed offsets tile positions by up to 2% of frame width/height and changes at least every 3 s with random phase And across any contiguous 5 s window, no overlay glyph remains at the same pixel coordinates for more than 250 ms And cropping up to 25% from any single edge still results in visible watermark text within the cropped viewport
Playback State Resilience: Quality Switches and Full-Screen
Given watermarking is enabled When the viewer toggles full-screen, resizes the embed, changes device pixel ratio, seeks, pauses, or changes playback quality/bitrate Then the overlay reflows and scales to maintain the same relative coverage (±5%) within 200 ms of the event And the overlay remains synchronized with the video frame with no visible tearing or single-frame disappearance during transitions And timestamp continuity is preserved across seeks (no backward time jumps other than the seek target) and resumes updating within 500 ms after seek And on full-screen, coverage and tile density remain consistent with windowed mode (±5% variance)
Policy Enforcement: Per-Asset and Domain-Scoped Watermark Rules
Given an asset has a policy configured in ClipSpark When policy is set to "Watermark on external domains only" with allowlisted domains Then embeds loaded on non-allowlisted top-level origins render the watermark and embeds on allowlisted origins do not And subdomain matching follows the configured rule (exact or wildcard) and is enforced consistently And an asset-level override can force watermark on/off regardless of domain policy and takes precedence when enabled And policy changes propagate to new sessions within 60 seconds and to existing sessions on next player reload And all policy decisions are logged with asset ID, domain, viewer ID (if present), and decision outcome
Security: Server-Signed Watermark Parameters and Client Tamper Resistance
Given ClipGuard watermarking is required by policy When the embed loads Then the player obtains watermark configuration from ClipSpark signed with an expiring token (TTL configurable, default ≤ 1 hour) And if the signature is missing, expired, or invalid, playback is blocked before first frame with an error code and telemetry event And removing or altering watermark-related query params, local storage, CSS, or DOM nodes does not result in playback without a watermark; either the player restores the overlay or blocks playback And the overlay is rendered via a secured canvas/SVG layer tied to the video rendering pipeline; attempts to hide the layer trigger playback pause and error telemetry And no unsigned client-supplied parameters can disable or weaken the watermark (opacity, density, angle, jitter)
SSO Integration: Identity Resolution for Watermarking
Given SSO-gated playback is enabled for an asset When an unauthenticated viewer opens the embed Then playback does not start and the viewer is prompted to authenticate via the configured SSO provider And upon successful SSO, the watermark uses attributes mapped in ClipSpark in priority order: displayName > email > subject ID And if no attributes are available, the watermark uses a deterministic pseudo-identifier "Guest-{shortSessionId}" And if SSO session expires mid-playback, watermark identity refreshes within 5 seconds of reauthentication And identity used in the watermark is included in server logs for the session with a correlation ID
Performance: Negligible Impact via GPU-Accelerated Rendering
Given a mid-tier desktop and a modern mobile device baseline When watermarking is enabled during 1080p30 playback Then player start time added by watermark initialization is ≤ 100 ms at p95 and ≤ 200 ms at p99 And steady-state dropped frames attributable to the watermark are ≤ 1% at p95 and ≤ 2% at p99 And additional CPU utilization attributable to the watermark is ≤ 5 percentage points (desktop) and ≤ 8 percentage points (mobile) at p95 And memory overhead of the watermark subsystem is ≤ 20 MB at p95 And rendering path uses GPU acceleration when available and falls back gracefully without violating the above thresholds
Domain Whitelisting & Signed Embed Tokens
"As a security administrator, I want embeds to work only on approved domains and expire when needed so that content can’t be hot-linked or scraped elsewhere."
Description

Secure embeds with domain allowlists and signed, time-bound tokens. Each embed code includes a JWT (or similar) that encodes asset ID, policy flags (SSO required, watermark on), expiration, and optional viewer claims. At playback, the player validates referrer/origin against an allowlist and rejects mismatches. Support single-use links, max concurrent sessions, and rapid revocation via a server-side denylist. Provide admin UI for managing allowed domains, rotating keys, and auditing recent embed validations, with webhook events for policy violations.

Acceptance Criteria
Domain Whitelisting Enforcement
- Given an embed configured with allowed domains ["example.edu", "*.partner.org"], when the player loads within an iframe on https://courses.example.edu/xyz, then playback initializes and the validation API returns 200 with origin_valid=true. - Given the same configuration, when the embed is loaded from https://blog.partner.org/post-1, then playback initializes and validation API returns 200. - Given the same configuration, when the embed is loaded from https://evil.com/page, then the player refuses to start, shows error code ORIGIN_NOT_ALLOWED, and no media segments are requested. - Given no Referer header but a postMessage origin of https://courses.example.edu, then validation passes. - Given a subdomain not matching the configured wildcard (e.g., https://sub.sub.partner.org when only *.partner.org is allowed), then validation fails with ORIGIN_NOT_ALLOWED. - Given an admin updates the allowlist and saves, when a new session is created, then the updated rules take effect within 60 seconds.
Token Validation and Policy Flag Enforcement
- Given a token with kid referencing an active key, asset_id matching the requested asset, exp 10 minutes in the future, sso_required=false, and watermark=true, when the player verifies the token, then signature verification succeeds and playback starts with a visible watermark overlay. - Given a token signed with an unknown or retired key, when verification runs, then playback is blocked with TOKEN_INVALID_SIGNATURE and 403. - Given a token expired (exp in the past) or not-yet-valid (nbf in the future) beyond ±60 seconds clock skew leeway, then playback is blocked with TOKEN_EXPIRED or TOKEN_NOT_YET_VALID and 403. - Given sso_required=true and the viewer is not SSO-authenticated, then playback is blocked with SSO_REQUIRED and no media requests are made. - Given sso_required=true and the viewer has an active SSO session, then playback is allowed and proceeds normally. - Given the token asset_id does not match the embed's asset, then playback is blocked with ASSET_MISMATCH and 403.
Single-Use Token Enforcement
- Given a token with single_use=true, when the first playback starts, then the token is marked consumed upon the first successful manifest request. - Given the same token is reused in a new browser or device within its validity window, then the player blocks playback with TOKEN_REPLAY_DETECTED and 403. - Given the same token is reused in the same browser session after stopping playback, then playback is blocked with TOKEN_REPLAY_DETECTED. - Given two near-simultaneous start requests with a single-use token, then at most one session succeeds; the other fails with TOKEN_REPLAY_DETECTED. - Given single_use=false (default), then tokens may be reused until expiration without replay errors.
Max Concurrent Sessions Limit
- Given policy max_concurrent=2 enforced per (asset_id + viewer_id if present, else per token jti), when two sessions are active for the same key, then a third start attempt is rejected with CONCURRENCY_LIMIT_EXCEEDED and 429, and no media segments are served. - Given one of the active sessions ends or becomes idle beyond a 90-second heartbeat timeout, then the viewer can start a new session successfully. - Given the viewer is anonymous (no sub claim) and using a token with jti=abcd, then only up to two concurrent sessions across devices are permitted for that token. - Given an admin updates max_concurrent to 3 in policy, then new session evaluations reflect the updated limit within 60 seconds.
Rapid Revocation via Server-Side Denylist
- Given an active token with jti=abc123, when an admin adds that jti to the denylist via API or UI, then any new playback attempts with that token are blocked within 10 seconds with TOKEN_REVOKED and 403. - Given an active session using a now-revoked token, then the session is terminated within 30 seconds via heartbeat rejection and the player displays TOKEN_REVOKED. - Given a denylist entry targeting an asset_id, then any tokens for that asset are blocked on new session attempts. - Given an admin removes an entry from the denylist, then new sessions are allowed within 60 seconds.
Admin UI: Domain Management, Key Rotation, and Validation Audit
- Given an admin with appropriate role, when they add a domain entry "*.school.edu" and click Save, then the allowlist updates and is used by validation within 60 seconds. - Given an admin attempts to add an invalid domain (e.g., "http://bad"), then the UI prevents save and shows an inline validation error. - Given an admin initiates key rotation, then a new signing key with kid is generated and set active; newly issued tokens use the new kid; tokens signed with the previous key continue to validate during a configurable grace period (default 7 days). - Given the grace period ends and the old key is deactivated, then tokens signed with that key are rejected with TOKEN_INVALID_SIGNATURE. - Given an admin opens Validation Audit, then they can filter by outcome (pass/fail), reason_code, asset_id, domain, and timeframe, and view entries with timestamp, asset_id, domain, reason_code, token_kid, and redacted viewer_claims. - Given audit data retention is 30 days, then events older than 30 days are not visible in the UI.
Webhook Events for Policy Violations and Revocations
- Given a policy violation occurs (e.g., ORIGIN_NOT_ALLOWED, TOKEN_INVALID_SIGNATURE, TOKEN_EXPIRED, TOKEN_REVOKED, CONCURRENCY_LIMIT_EXCEEDED, TOKEN_REPLAY_DETECTED), then a webhook is delivered to the configured endpoint within 5 seconds containing id, type, timestamp, asset_id, domain, reason_code, kid, and jti, with PII fields redacted. - Given the endpoint responds non-2xx, then the system retries with exponential backoff for up to 24 hours (minimum 10 attempts), signing each request with an HMAC using the webhook secret and including a SHA-256 signature header. - Given duplicate deliveries due to retries, then the event id enables idempotent handling by receivers. - Given an admin rotates the webhook secret, then deliveries use the new secret within 60 seconds, while the previous secret remains valid for 10 minutes to allow rollover. - Given the webhook is disabled in the UI, then no events are sent while violations continue to appear in the Validation Audit.
Platform Integrations: oEmbed, Notion, LMS (LTI 1.3)
"As an educator, I want ClipSpark cards to embed seamlessly in Notion and our LMS so that my students can watch and interact without extra steps."
Description

Offer first-class integrations for major platforms. Provide an oEmbed endpoint for automatic card rendering in WordPress and other CMS. Deliver a Notion-compatible embed that respects Notion’s sandbox and resizing APIs. Implement LTI 1.3 Advantage for LMS (Canvas, Moodle, Blackboard) to support roster-aware access, gradebook passback (optional), and SSO without third-party cookies. Supply copy-paste snippets and platform-specific setup guides, plus metadata tags (Open Graph/Twitter) for link previews. Validate embeds across modern browsers and platform constraints with automated integration tests.

Acceptance Criteria
oEmbed Endpoint Renders Clip Card in WordPress
Given a WordPress 6.x site with oEmbed discovery enabled When an editor pastes a public ClipSpark card URL into the editor Then WordPress fetches https://clipspark.com/oembed with the URL and receives valid oEmbed 1.0 JSON containing type="rich", version="1.0", provider_name="ClipSpark", provider_url, title, thumbnail_url, width, height, and html And the html renders a responsive iframe that displays the card and is interactive within 2.0s p95 on broadband And the embed sets no third-party cookies and makes no tracking calls to third-party domains And HTTP responses include Cache-Control: public, max-age=3600 and an ETag, and support conditional requests (304) And for private or invalid card URLs, the endpoint returns 404 with an error message, and WordPress displays a fallback link And if the card is SSO-gated, the embed shows a "Sign in to view" overlay and begins playback within the same iframe after successful sign-in
Notion Embed Respects Sandbox and Auto-Resizes
Given a Notion page with an Embed block pointed at a ClipSpark card URL When the page loads Then the iframe includes sandbox attributes compatible with Notion and loads without console errors And the embed uses postMessage-based resizing so height adjusts to content within 200ms of layout changes with no vertical scrollbars And the card is fully functional (play/pause/seek/captions/highlights) and keyboard accessible within Notion's sandbox And the iframe is responsive (100% width) and maintains a minimum width of 320px without clipping UI And no third-party cookies are set; local storage access is limited to the iframe's first-party context And if the card is SSO-gated, a sign-in prompt appears and completes via a popup/redirect flow permitted by Notion; playback starts without leaving Notion
LTI 1.3 Launch: Roster-Aware Access and Optional Grade Passback
Given an LMS (Canvas, Moodle, or Blackboard) configured with ClipSpark as an LTI 1.3 tool (issuer, client_id, JWKS, redirect URIs) When an instructor performs deep linking to add a ClipSpark card as a resource or assignment Then ClipSpark returns a valid LtiDeepLinkingResponse with a content item that includes the resource link, title, and optional line item details When a learner launches the link via OIDC login Then id_token validation (iss, aud, nonce, signature, exp) succeeds and the user is created/mapped without third-party cookies And NRPS is used to confirm enrollment; only enrolled users gain access; roles are mapped to Viewer/Instructor correctly And ClipGuard watermarking is applied if enabled And, if graded is enabled, an AGS LineItem is created (or reused) and a Score is passed within 5s of completion; updates are idempotent and retried with exponential backoff up to 3 times And if grades are disabled, no AGS calls are made And all launches and passbacks are logged with request IDs and are viewable in admin audit logs
SSO-Gated Playback Without Third-Party Cookies (All Embeds)
Given a browser with third-party cookies blocked (Safari default, Firefox strict, Chrome incognito) When a user loads a ClipSpark embed (oEmbed/Notion/custom iframe) for a gated card while not authenticated Then the embed presents a "Sign in to view" CTA and completes authentication using a first-party redirect or popup + postMessage/PKCE exchange without setting third-party cookies And upon successful authentication, the embed receives a short-lived access token via postMessage and starts playback without a full page reload And if the user closes the auth window, the embed remains on the gated state with an actionable retry option And network requests show no Set-Cookie on third-party contexts; all auth cookies are SameSite=Lax/Strict on clipspark.com
Copy-Paste Snippets and Platform Setup Guides Available In-App
Given a ClipSpark card owner viewing the Share/Embed modal When they open the Embed tab Then they can copy: (a) the public card URL (oEmbed-compatible), (b) a responsive iframe snippet, and (c) LMS Deep Link instructions And a Notion-specific tip is shown with steps to add an Embed block and paste the URL And platform setup guides for WordPress, Notion, Canvas, Moodle, and Blackboard are linked with versioned instructions and screenshots And all links return HTTP 200, and the copied snippets render the same card when pasted into a blank HTML page And the modal confirms "Copied" with ARIA live region support for screen readers
Link Previews via Open Graph and Twitter Cards
Given a public ClipSpark card URL When a crawler from Slack, LinkedIn, X (Twitter), or Facebook fetches the landing page Then the HTML contains valid og:title, og:description, og:image (>=1200x630), og:url, and twitter:card=summary_large_image And the preview renders with correct title, description, and image in each platform’s validator tools And for private/SSO-gated cards, metadata uses a non-sensitive poster image and generic description without leaking transcript content And metadata updates propagate within 60 seconds after editing the card by honoring cache busting headers (Cache-Control/ETag)
Automated Integration Tests Across Platforms and Browsers
Given the CI pipeline runs nightly When integration tests execute Then Playwright-based E2E suites cover: WordPress oEmbed render, Notion embed load/resize, Canvas/Moodle/Blackboard LTI deep link and launch, and gated playback flows And tests run on Chrome, Firefox, and WebKit with a pass rate >= 95% over the last 10 runs and flake rate < 2% And failures capture HARs, screenshots, and console logs and are uploaded as artifacts And a summary report is posted to the team channel with scenario-level pass/fail and p95 render times for embeds
Accessibility & Caption Controls (WCAG 2.2 AA)
"As a viewer with accessibility needs, I want fully navigable embeds with customizable captions so that I can consume content comfortably and effectively."
Description

Ensure the embedded card and player meet WCAG 2.2 AA. Provide full keyboard navigation, visible focus states, ARIA labels, and screen-reader-friendly structure. Include caption and transcript controls with language selection, adjustable caption styling (size, contrast, background), and support for audio descriptions. Maintain sufficient color contrast in all themes, support pause/stop for auto-advancing highlights, and respect reduced motion preferences. Validate with automated accessibility tests and manual audits, and publish an accessibility conformance report (VPAT) for enterprise procurement.

Acceptance Criteria
Keyboard-Only Playback and Settings Navigation
Given I am a keyboard-only user on an embedded ClipSpark card When the card loads Then focus starts on the card container with an accessible name And pressing Tab cycles through all interactive elements exactly once in a logical order (no traps), including: Play/Pause, Seek Bar, Volume, Captions, Settings, Language, Transcript toggle, Next/Previous highlight, and any Menu/Dialog triggers And Enter/Space activates focused controls; Arrow keys adjust sliders/menus; Escape closes any open menu or modal And a visible focus indicator (>= 2px thickness and >= 3:1 contrast against adjacent colors) is present on all focusable elements And a "Skip to player controls" link is focusable as the first tabbable element and moves focus appropriately
Screen Reader Compatibility for Player Controls
Given a screen reader user activates the embedded player When navigating controls using screen reader quick-nav and forms mode Then every control exposes correct name, role, and value/state via native semantics or ARIA (e.g., buttons, sliders, menus, toggles) And the player region exposes a programmatic label including media title and duration And captions and transcript toggles announce their current state (on/off), selected language, and count of available languages And dynamic updates (menus opening, errors, SSO prompts) are announced via appropriate ARIA roles (menu, alert, status) without duplicate readings And decorative elements are hidden from assistive tech and reading order matches logical/visual order
Captions, Transcript, and Audio Description Controls & Styling
Given a video has multiple caption tracks and an audio description track When the user opens Captions/Settings Then they can select caption language; the change applies within 1 second and persists for 30 days per domain And the user can enable/disable audio description; when enabled, the description track plays in sync with <=100 ms drift And the user can adjust caption size (small/medium/large), font (sans/serif), text color, and background color/opacity; changes preview immediately and apply within 1 second And caption text maintains >= 4.5:1 contrast against its background at all times, including over video And a transcript panel can be opened, is keyboard navigable, lists timestamped entries, and activating an entry jumps playback to that time and returns focus to the player context
Auto-Advancing Highlights Pause Control and Reduced Motion
Given a highlight reel with auto-advance is playing When playback starts or a highlight ends Then a visible and accessible "Pause Auto-Advance" control is present and operable by keyboard and screen reader And users can pause or stop auto-advance; when paused, highlights do not change automatically; the setting persists for the session And if prefers-reduced-motion is detected, non-essential motion and transitions are disabled and auto-advance animations are removed And no content moves, blinks, or auto-updates for more than 5 seconds without user-controllable pause/stop/hide per WCAG 2.2.2
Color Contrast and Theming Compliance
Given the embed card is displayed in light, dark, and high-contrast themes When rendering UI text, icons, and component boundaries Then contrast meets WCAG 2.2 AA: >= 4.5:1 for normal text, >= 3:1 for large text and graphical objects/UI components And focus indicators maintain >= 3:1 contrast against adjacent colors And ClipGuard watermark never reduces caption or control legibility; captions maintain >= 4.5:1 contrast using a background box if needed And automated contrast checks report zero axe color-contrast violations across all supported themes
Accessible SSO-Gated Playback Modal
Given playback is SSO-gated and the user is unauthenticated When the SSO modal opens Then focus moves to the modal, is trapped within until dismissed, and returns to the trigger on close And the modal has a programmatic label and description; all inputs are labeled; errors are conveyed via role=alert and associated to fields And the modal is fully operable with keyboard; Escape closes the modal without side effects; screen readers announce state changes And any authentication time limits can be extended at least 10 times, with >= 20 seconds warning before expiry
Automated and Manual Accessibility Validation & VPAT
Given the latest build of the Embed Card and player When running automated checks Then axe-core reports zero serious/critical violations and <= 2 minor per view; pa11y exits 0; Lighthouse accessibility score >= 95 And manual audits on NVDA+Firefox, JAWS+Chrome, and VoiceOver+Safari validate WCAG 2.2 AA success criteria relevant to the player And keyboard-only and screen reader smoke tests pass on Windows, macOS, and one mobile screen reader (TalkBack or VoiceOver) And an updated WCAG 2.2 AA VPAT is published in accessible HTML and PDF with date >= 2025-09-13 and linked from the product site

Card Packs

Bundle related Clip Cards into a swipeable carousel or sequenced mini-playlist with a single share link. Auto-order by engagement or narrative structure to keep audiences binging context-rich moments instead of bouncing.

Requirements

Pack Composer & Management
"As a content creator, I want to bundle selected Clip Cards into a named pack with a defined order so that I can deliver a cohesive set of highlights through one shareable artifact."
Description

Enable users to create, name, and describe Card Packs by selecting existing Clip Cards from ClipSpark libraries; support drag-and-drop ordering, bulk add/remove, and max/min card constraints; allow mode selection (swipeable carousel or mini-playlist) and pack metadata (cover image, tags, access level). Persist packs as references to source Clip Cards so updates to captions or media propagate automatically. Provide draft/save/publish states, validation (missing media, captions, mixed aspect ratios), and a canonical pack ID for routing and retrieval. Integrate with ClipSpark’s media pipeline, captioning, and CDN for efficient load and playback. Output a single shareable artifact upon publish.

Acceptance Criteria
Create and Save Draft Pack
Given a logged-in user opens Pack Composer, When they click "New Pack", enter a unique name (3–80 chars) and optional description (0–500 chars), and click "Save Draft", Then a new pack is created with state "Draft", owner set to the user, createdAt/updatedAt timestamps recorded, and it appears in the user's Packs list. Given a user attempts to save a pack name that already exists in the same workspace, When they click "Save Draft", Then the save is blocked and an inline error indicates the name must be unique. Given a draft pack has unsaved changes, When the user attempts to navigate away or close the tab, Then the app prompts to Save or Discard changes and proceeds according to the user's choice.
Bulk Select, Add/Remove, and Card Count Constraints
Given existing Clip Cards in the user's library, When the user bulk-selects N cards and clicks "Add to Pack", Then all selected cards are added in the selection order without duplicates. Given a pack contains cards, When the user selects multiple cards within the pack and clicks "Remove", Then all selected cards are removed in one action and an Undo option is available for 10 seconds. Given organization-defined pack_min_cards and pack_max_cards are in effect, When the user attempts to publish a pack with a card count outside the allowed range, Then publish is blocked and an error displays the current count and the allowed range; When the count is within range, Then publish is permitted (subject to other validations).
Manual Reordering and Auto-Order by Engagement/Narrative
Given a pack with two or more cards, When the user drags a card to a new position and drops it, Then the new order is persisted and reflected immediately in preview. Given the user toggles auto-order to "Engagement", When applied, Then cards reorder descending by engagement score with deterministic tie-breaking, and the UI displays a badge "Auto-ordered: Engagement". Given auto-order is enabled, When the user switches back to "Manual" mode, Then the last saved manual sequence is restored and becomes the active order.
Mode Selection: Carousel vs Mini-Playlist Playback
Given a pack in composer, When the user selects "Carousel" mode and previews, Then the preview renders swipe/arrow navigation and per-card independent playback with captions aligned to timestamps. Given the user selects "Mini-Playlist" mode and previews, Then a single player plays cards sequentially in the specified order with automatic transitions, continuous captions, and a visible progress indicator. Given a mode is selected at publish time, When the share link is opened on desktop and mobile, Then the public page honors the selected mode and the mode choice is persisted in pack metadata.
Pack Metadata, Access Level, and Validation Gates
Given the user sets pack metadata (cover image chosen or generated, up to 10 tags with each tag ≤ 30 chars, and access level Public/Unlisted/Private-Team), When saved, Then the metadata persists and is returned by the Pack API. Given one or more cards in the pack are missing media or captions, When the user clicks "Publish", Then publish is blocked and the UI highlights offending cards with specific reasons and a direct "Fix" action. Given the pack contains mixed aspect ratios, When the user clicks "Publish", Then a non-blocking warning describes letterboxing/cropping behavior with preview; the user may proceed or adjust before publishing.
Reference-Based Persistence and Update Propagation
Given packs persist references to source Clip Card IDs (not duplicated media/captions), When captions or media of any referenced card are updated, Then the pack reflects the updates on next render/API fetch without republishing the pack. Given a referenced card becomes unavailable due to deletion or permission changes, When the pack is opened or rendered, Then the pack indicates the missing card, excludes it from playback, and surfaces a "Resolve missing card" notice to the owner.
Publish: Canonical Pack ID, Share Link, and CDN Delivery
Given a valid pack passes all blocking validations, When the user clicks "Publish", Then the system assigns an immutable canonical Pack ID and generates a single shareable URL and embed code for the pack. Given the share link is accessed by an authorized viewer, When the page loads over a 10 Mbps connection, Then initial HTML TTFB is ≤ 1.5s via CDN, first frame of the first card starts ≤ 2.0s, and subsequent cards prefetch for gapless playback. Given the pack access level is Private/Team, When an unauthorized user opens the share link, Then access is denied with HTTP 403 and no media or caption assets are delivered; Public and Unlisted packs are accessible without authentication (subject to link possession).
Auto-Ordering Engine (Engagement & Narrative)
"As a marketer, I want my pack to auto-arrange based on what keeps viewers engaged so that audiences keep swiping instead of dropping off."
Description

Offer automatic ordering modes that sequence cards by engagement (views, completion rate, swipe-through rate, CTR) or by narrative structure (chronological by source timestamp, topic continuity via embeddings and transcript cues). Allow users to toggle mode per pack, lock specific cards in place, and blend manual and auto-ordering. Recompute order on publish or on demand, with versioned snapshots for auditability. Expose ordering rationale and expected impact on retention. Integrate with analytics datastore and ClipSpark’s transcript/embedding services for topic cohesion.

Acceptance Criteria
Auto-Order by Engagement Metrics
Given a Card Pack with at least 5 cards and non-null analytics metrics (views, completion rate, swipe-through rate, CTR) available from the analytics datastore for the last 30 days for each card And Engagement mode is selected for the pack When the user triggers "Recompute Order" Then each card's engagement score is computed using the configured weighting shown in the rationale And cards are sorted in descending order of engagement score And ties are broken by higher completion rate, then higher CTR, then most recent publish date, then lexicographic card ID And the resulting order matches the order implied by the per-card scores displayed in the rationale And the recompute completes within 2 seconds for packs up to 50 cards (P95)
Auto-Order by Narrative: Chronological
Given all cards have source timestamps (start and end) mapped to the original video And Narrative mode is set to Chronological When the user triggers "Recompute Order" or publishes the pack Then cards are sorted ascending by start timestamp; for equal starts, ascending by end timestamp And cards with missing timestamps are placed after all timestamped cards and are flagged in the rationale as "No timestamp" And the order is stable across repeated recomputes when inputs are unchanged
Auto-Order by Narrative: Topic Continuity
Given embeddings and transcript cues are available for all cards from ClipSpark services And Narrative mode is set to Topic Continuity When the user triggers "Recompute Order" Then the system orders cards to maximize the sum of cosine similarity between consecutive cards And the rationale shows per-adjacency similarity values and the total objective score And for packs of up to 8 cards, the produced order's total similarity is within 1% of the brute-force optimal order And if embeddings are unavailable for any card, the system falls back to Chronological and notes the fallback in the rationale
Lock Positions and Blend Manual + Auto
Given the user has locked one or more cards to specific positions in the pack And other cards remain unlocked When any auto-order recompute occurs (Engagement or Narrative mode) Then locked cards remain in their exact positions And unlocked cards are ordered by the selected mode and inserted into remaining slots without shifting locked cards And if two cards are locked to the same position, the system blocks saving the configuration and displays an actionable error with the conflicting card IDs And ties among unlocked cards are broken by their previous manual relative order if present, otherwise by chronological timestamp
Recompute on Publish and On-Demand with Versioning
Given a pack with an ordering mode selected When the user clicks "Recompute Order" twice with different underlying inputs (e.g., analytics metrics) Then two distinct ordering snapshots are stored with immutable version IDs, timestamps, mode, inputs hash, and per-card rationale And the user can view a list of versions and restore a prior version And upon restoration, the pack's active order exactly matches the restored snapshot and a new version is created to reflect the restore action And an audit log entry is recorded for each recompute and restore with actor, time, and inputs hash
Ordering Rationale and Retention Impact
Given a recomputed order exists in Engagement or Narrative mode When the user opens "View Ordering Rationale" Then the UI displays for each card the metrics/similarities used, the computed score, tie-breakers applied, and position change from the previous version And a pack-level panel shows the selected mode, weighting/config parameters, and an estimated retention uplift percentage versus a chronological baseline, with a confidence interval And the values shown reconcile exactly with the metrics fetched from the analytics datastore for the specified time window And if estimation cannot be computed due to insufficient data, the UI states "Insufficient data" and hides the uplift value
Graceful Degradation and Performance SLAs
Given intermittent latency or partial outages in the analytics datastore or embedding service When the user triggers "Recompute Order" Then the system retries failed reads up to 3 times with exponential backoff and surfaces any remaining data gaps in the rationale And if analytics data is unavailable, the system falls back to Narrative: Chronological; if embeddings are unavailable for Topic Continuity, it falls back to Chronological And recompute completes within 2 seconds P95 for packs up to 50 cards and within 5 seconds P95 for packs up to 200 cards And any fallback or retry event is recorded in observability logs with correlation IDs
Swipeable Carousel & Mini-Playlist Player
"As a viewer, I want to swipe through highlights or watch them play continuously so that I can quickly consume the best moments without friction."
Description

Deliver a responsive web player that renders Card Packs as a mobile-first swipeable carousel and a desktop-friendly mini-playlist with click/keyboard navigation. Support autoplay next, looping, captions on/off, progress indicator, and resume from last viewed card. Provide deep linking to a specific card index and lazy loading for fast time-to-first-frame. Ensure accessibility (ARIA labels, focus states, reduced motion), localization of UI labels, and compatibility with ClipSpark’s caption formats and CDN delivery. Enable CTA overlays per card when present.

Acceptance Criteria
Mobile Swipeable Carousel
Given the viewport width is <= 768px When the Card Pack player loads Then it renders a single-card, full-width swipeable carousel with no playlist sidebar Given a horizontal drag of >= 30px within 600ms When released Then the active card advances by 1 in the drag direction and snaps within 200ms Given the first or last card is active When the user swipes beyond the bounds Then the carousel resists and the index remains unchanged Given device orientation changes When the player is visible Then the current card index is preserved and layout reflows within 300ms
Desktop Mini-Playlist with Keyboard Navigation and Localized UI
Given the viewport width is >= 1024px When the player loads Then a mini-playlist panel is visible showing all card thumbnails/titles and the active card is highlighted Given keyboard focus is on the player When Left/Right or Up/Down is pressed Then the selection moves to the previous/next card and Enter/Space starts playback of the focused card Given focus moves through controls When Tab/Shift+Tab is used Then all actionable elements receive a visible focus state and the focus order matches visual order Given a screen reader is used When the player is announced Then the playlist uses role=listbox with options exposing aria-selected and all buttons expose accurate aria-labels Given a locale code is provided (e.g., es-ES, ar) When the player loads Then all UI labels/tooltips/ARIA strings render in that locale with English fallback and RTL locales mirror layout correctly
Playback Continuity: Autoplay, Looping, Progress, Resume
Given autoplay is enabled and the OS prefers-reduced-motion is not set When a card ends Then the next card starts within 500ms Given looping is enabled When the last card ends Then playback continues at the first card within 500ms; otherwise playback stops and a Replay Pack control is shown Given the player is visible When a card plays Then a per-card time progress bar and a pack progress indicator (e.g., 3/12) update in real time Given the user has watched at least 3 seconds When the pack page is reopened without a deep link Then playback resumes at the last viewed card and timestamp within 1 second
Captions Toggle and Format Compatibility
Given a pack includes captions When the player loads Then a CC control is visible and the default state follows the saved user preference or is ON if no preference exists Given CC is toggled ON When playback runs Then captions render with timing sync within ±200ms of the audio Given multiple caption tracks exist When the captions menu is opened Then available tracks are listed by language and the selected track persists across card changes Given ClipSpark caption formats (WebVTT, SRT) are provided When a card loads Then the captions track parses and displays without errors
Deep Linking to Card Index and Time
Given a URL with ?c=<0-based-index>&t=<seconds> When opened Then the player loads at the specified card and starts at the specified timestamp (or 0 if t is missing) Given the URL contains an out-of-range c When opened Then the index clamps to the nearest valid card Given the user navigates cards or seeks time When state changes Then the URL is updated using history.pushState within 200ms without a full page reload Given the user clicks Share current moment When clicked Then a canonical URL with c and t for the current card and second is copied to the clipboard
Lazy Loading and CDN Performance
Given the pack loads over a throttled 4G profile (150ms RTT, 1.6Mbps) When the first card is requested Then the first frame is visible within 1.5s for at least 95% of test runs Given the player is on card i When idle Then only media for cards i-1, i, and i+1 and their captions/thumbnails are preloaded; all others are deferred Given media is served from the ClipSpark CDN When requested Then requests use HTTPS, support range requests, succeed with CORS, and if HLS fails the MP4 fallback loads automatically Given the user navigates to the next card When the transition begins Then prefetch for the next+1 card starts with total prefetch payload under 200KB
CTA Overlays per Card
Given a card has a CTA configured with text and target URL When playback reaches the CTA start time Then an overlay appears, is keyboard focusable, and does not obscure the captions area Given the CTA overlay is visible When the primary CTA is activated by click, Enter, or Space Then the target opens in a new tab with noopener noreferrer and playback pauses Given the CTA overlay is visible When the user dismisses it Then it hides immediately and remains dismissed for the remainder of the card unless the card is replayed
One-Link Share & Embedding
"As a host, I want a single link and embed for a pack so that I can promote it across channels without managing multiple assets."
Description

Generate a canonical share URL for each published pack with customizable slug, Open Graph/Twitter metadata (title, description, cover, first card preview), and UTM parameter support. Provide responsive embed codes (iframe/web component) with theme options, start-at card, and autoplay controls. Implement privacy settings (public, unlisted, workspace-only), link shortener, and geo-aware CDN routing for low-latency playback. Ensure link-level analytics attribution and compatibility with major platforms and CMSs.

Acceptance Criteria
Canonical Share URL & Custom Slug
Given a published Card Pack without a provided slug When the user clicks Generate Link Then a unique canonical URL in the format https://clipspark.com/p/{auto-slug} is created and returns HTTP 200 Given a published Card Pack and a requested custom slug matching ^[a-z0-9-]{3,60}$ When the user saves the slug Then the canonical URL uses the requested slug if not already taken And invalid slugs are rejected with a clear validation message And slug conflicts return HTTP 409 with an availability error And the canonical URL resolves within 500 ms p95
Social Metadata Unfurl (OG/Twitter)
Given a canonical pack URL When requested by social crawlers (Facebook, LinkedIn, X/Twitter, Slack/Discord) Then the HTML includes valid Open Graph and Twitter Card tags: og:title, og:description, og:image, og:url, twitter:card=summary_large_image And og:image is HTTPS, >= 1200x630, and < 2 MB And the title/description match the pack metadata And the image/preview corresponds to the first card And platform debuggers/unfurlers display the expected title, description, and image
UTM Support & Link-Level Analytics Attribution
Given a canonical or shortened share URL appended with utm_source, utm_medium, utm_campaign, and optional custom parameters When a viewer opens the link or an embed generated from the link Then all UTM parameters persist to the playback URL without double-encoding And the view/play events are recorded with a unique link_id tied to the originating share URL And analytics attribute engagement (views, watch time, clicks) to the link_id and pack And unknown UTM parameters are preserved end-to-end
Responsive Embeds with Theme, Start Card, Autoplay & CMS Compatibility
Given a published pack When the user copies the iframe or web component code Then the embed renders responsively at 100% width with a default 16:9 aspect ratio and supports configurable aspect ratios And supports options theme={light|dark|auto}, startCard={index|id}, autoplay={true|false} And when pasted into WordPress, Notion, Squarespace, and Webflow/Medium, the embed renders and plays successfully And when startCard is set, playback begins at the specified card And when autoplay=true, playback auto-starts muted where required by browser policy, otherwise on user gesture
Privacy Settings Enforcement & Indexing Controls
Given privacy=Public When any user accesses the share URL or embed Then content is viewable without authentication and included in sitemaps Given privacy=Unlisted When any user with the URL accesses the share URL or embed Then content is viewable without authentication, excluded from sitemaps, and returns X-Robots-Tag: noindex, nofollow Given privacy=Workspace-Only When an unauthenticated or external user accesses the share URL or embed Then access is denied with HTTP 401/403 and no content or sensitive metadata is exposed in OG tags And authenticated workspace members can view normally
Link Shortener Generation & Redirect Behavior
Given a published pack with a canonical URL When the user selects Shorten Link Then a short HTTPS URL (length ≤ 24 chars) is generated And the short URL 301-redirects to the canonical URL while preserving all query parameters (including UTM) And the redirect completes in ≤ 200 ms p95 And if the pack is unpublished or deleted, the short URL returns HTTP 404
Geo-Aware CDN Routing & Playback Latency
Given viewers in North America, Europe, and APAC When they load the canonical URL or embed Then requests are routed to the nearest CDN edge And p95 TTFB for the pack page and media manifests is < 300 ms per region And p95 time-to-first-frame of video is < 2 s on a 5 Mbps connection And on edge failure, traffic fails over to a healthy edge within 1 s without user action
Pack-Level Analytics & Insights
"As a creator, I want to see where viewers drop off in a pack so that I can tweak ordering and content to improve retention."
Description

Capture and surface per-pack and per-card metrics including impressions, plays, average watch time, completion rate, swipe-through rate, exit card, and CTA click-through. Visualize drop-off by card index and provide comparisons across auto-ordering modes and time ranges. Enable CSV export, scheduled email reports, and webhooks for downstream tools. Respect privacy/consent settings and implement sampling/aggregation for high volume. Integrate with existing ClipSpark analytics pipeline and identity/tracking.

Acceptance Criteria
Accurate Metric Capture for Packs and Cards
Given a published Card Pack with tracking enabled and a viewer session, When the share link loads, Then increment pack_impressions by 1 once per viewer-session within a 30-minute rolling window. Given a viewer starts playback on any card in the pack, Then increment pack_plays by 1 once per viewer-session, and increment that card's plays by 1. Given playback progresses, Then accumulate watch_time per card and per pack; pack_average_watch_time equals total_watch_time_across_all_cards / pack_plays. Given a viewer watches a card to 90% or more, Then mark that card as completed; pack_completion_rate equals percentage of pack_plays where the last card is reached and watched to ≥90%. Given a viewer swipes from card i to i+1, Then increment swipe_through for card i; swipe_through_rate equals swipe_through / card i impressions. Given a viewer exits on a card, Then increment exits for that card and expose exit_card as the card index with highest exits for the selected time range. Given a viewer clicks a CTA on a card, Then increment cta_clicks and compute cta_ctr as cta_clicks / card impressions for that card. Given high-volume traffic exceeding 10,000 events/min per pack, When sampling activates at a dynamic rate p, Then all surfaced metrics display sample_rate p and extrapolated counts within ±2% of ground truth in backfill audits. Given duplicate events within 5 seconds with identical viewer_id, card_index, and event_type, Then deduplicate and count once.
Drop-off Visualization by Card Index with Filters
Given a selected pack and time range, When the Analytics view loads, Then display a chart of viewer count per card index with cumulative drop-off percentages. Given filter selections for device, referrer, and geography, Then update the visualization and underlying counts within 1 second for datasets ≤100k events. Given hover on a card index, Then show tooltip with impressions, plays, completes, exits, swipe_through_rate, and delta vs previous card. Given more than 50 cards, Then the chart groups card indices beyond 50 into buckets with drill-down available. Given a data latency SLA of 5 minutes, Then the chart labels the last processed timestamp and disables ranges beyond processed time.
Mode and Time-Range Comparison View
Given a pack with at least two auto-ordering modes, When two modes and two time ranges are selected, Then show side-by-side key metrics (impressions, plays, average watch time, completion rate, swipe-through rate, CTA CTR) and percent deltas. Given insufficient data (<100 plays per variant), Then display Insufficient data badges and suppress percent deltas. Given a mode change published at time T, Then comparisons attribute sessions to the mode active at session start and exclude pre-T sessions from post-T mode. Given an export from the comparison view, Then the CSV includes mode labels and time range segments.
CSV Export of Pack/Card Analytics
Given a user with Analytics:Export permission, When Export CSV is requested for a pack and time range, Then a CSV is generated within 2 minutes for ≤1M rows and made available for download for 7 days. Then the CSV schema includes: pack_id, pack_name, card_index, card_id, time_window_start, time_window_end, timezone, auto_order_mode, impressions, plays, average_watch_time_seconds, completion_rate, swipe_through_rate, exits, exit_card_flag, cta_clicks, cta_ctr, sample_rate, generated_at, version. Then all timestamps are ISO 8601 UTC; numeric columns use dot decimal; percentages expressed as decimals to 4 places; timezone column indicates reporting TZ. Then exports respect privacy/consent (exclude opted-out viewers), and rows derived from sampled data include sample_rate > 0. Given export size >1M rows, Then the export is chunked and delivered as a zip; Given a user lacks permission, Then the action is disabled and API returns 403.
Scheduled Email Analytics Reports
Given a user schedules a pack analytics report, When frequency is Daily or Weekly and a delivery time and timezone are set, Then emails are sent at the scheduled local time including top-line metrics and attachment links to CSV for the range. Then recipients must verify ownership via email before first delivery; unverified addresses are not sent. Then each email includes secure signed links expiring in 7 days and reflects the latest processed data as of send time. Given report pause or unsubscribe, Then deliveries stop within 24 hours. Given a pack is deleted or permissions revoked, Then scheduled sends fail gracefully and notify the owner.
Analytics Webhooks for Downstream Tools
Given a webhook endpoint configured with an HMAC-SHA256 secret, When events pack.analytics.updated or pack.export.ready occur, Then ClipSpark sends JSON payloads signed in the X-ClipSpark-Signature header with ISO timestamps and schema version. Then deliveries occur within 2 minutes of event creation; on 4xx responses no retries; on 5xx or timeouts retries up to 6 times with exponential backoff up to 1 hour. Then payloads include pack_id, auto_order_mode, time_range, metrics, sample_rate, last_processed_at, and idempotency_key; duplicate deliveries share the same idempotency_key. Given endpoint test, Then a test event can be sent and delivery status is logged. Given payload size >1 MB, Then events are summarized with a presigned URL to fetch full data.
Privacy, Consent, and Identity Compliance
Given viewers who opt out or send GPC/Do Not Track signals, Then their events are excluded from analytics and exports. Then IP addresses and device IDs are not stored in exports or webhooks; viewer identifiers are hashed and salted; PII is never included. Then region-aware processing ensures EU viewer events are processed and stored in EU-only data stores; exports and webhooks for EU data do not traverse non-compliant regions. Then data retention for raw events is max 90 days and aggregated metrics 25 months, configurable per workspace. Given existing ClipSpark identity/tracking, Then all events include org_id, workspace_id, pack_id, card_id, and viewer_id where available; unknown viewers are tracked as anonymous with stable session_id. Then analytics latency SLO is ≤5 minutes p95; event deduplication prevents double-counting within 5-second windows.
Collaboration, Drafts & Publishing Workflow
"As a team producer, I want to collaborate on packs and publish confidently so that our output is consistent and error-free."
Description

Support multi-user collaboration with roles (owner, editor, viewer), real-time presence indicators, and comments on specific cards within a pack. Provide draft mode with change history, suggested edits, and conflict resolution. Include a pre-publish checklist (captions present, media valid, privacy set, cover set) and create immutable published snapshots with rollback capability. Send notifications on mentions, approvals, and publishes. Integrate with ClipSpark workspaces and existing permission models.

Acceptance Criteria
Workspace Roles Enforce Collaboration Permissions on Card Packs
Given a Card Pack in a ClipSpark workspace with users assigned as Owner, Editor, and Viewer When the Owner accesses the pack Then they can create/edit/reorder/delete cards, change privacy, manage collaborators, view history, accept/reject suggestions, request/approve publish, publish, and delete the pack Given an Editor accesses the pack When they attempt to modify content Then they can create/edit/reorder/delete cards, leave comments, enter Suggest mode, and request approval to publish And they cannot change privacy, manage collaborators, delete the pack, or publish directly And any unauthorized action is disabled in UI and returns 403 via API Given a Viewer accesses the pack Then they can view the draft and published snapshots and leave comments And they cannot modify cards, privacy, collaborators, history, or publish state Given workspace-level permissions restrict access to the pack When a non-member or revoked user attempts access Then access is denied with 404/permission error and no data is leaked (title, cards, comments)
Live Collaboration: Real-Time Presence and Conflict Handling
Given two or more collaborators open the same Card Pack draft When each joins the editor Then presence avatars with names appear to all active users within 1 second And per-field edit indicators (cursor/selection) are shown with unique colors Given a user becomes inactive or disconnects When 10 seconds elapse without a heartbeat Then their presence indicator disappears for others Given two editors begin typing in the same card field within 2 seconds of each other When the conflict is detected Then the field shows “User X is editing” and applies a soft lock preventing silent overwrites Given offline or near-simultaneous saves create divergent content in the same field When either user attempts to save Then a merge dialog displays a diff of changes with options: Keep Mine, Keep Theirs, Manual Merge And no data is lost; the chosen resolution becomes the new version and is recorded in history
Card-Level Comments with @Mentions and Threading
Given a user (Owner/Editor/Viewer) opens a Card Pack draft When they add a comment on a specific card (and optional timestamp) Then the comment is anchored to that card, shows author and timestamp, and appears to other viewers within 2 seconds Given a comment thread exists When a user replies or marks it Resolved Then the thread displays in chronological order, updates status to Open/Resolved, and can be reopened by Owner/Editor Given a user types “@” in a comment When they search for a name Then autocomplete lists only users with access to the pack, and a selection inserts an @mention token Given a comment is edited or deleted by its author When the change is saved Then edits are allowed for 5 minutes after posting and show an “edited” indicator; deletions remove the comment but retain a redacted placeholder for audit
Draft Mode with Change History and Suggested Edits
Given a Card Pack is in Draft mode When any card content, order, captions, cover, or settings change Then a new version is recorded with author, timestamp, and a diff of changed fields And at least the last 50 versions are retained and viewable Given an Editor enables Suggest mode When they propose changes to a card Then the changes are saved as suggestions with inline markers and do not alter the live draft content until accepted Given suggestions exist When an Owner or Editor reviews them Then they can Accept or Reject each suggestion individually or in bulk, with an optional note And accepted suggestions apply changes and create a new version; rejected ones are archived and hidden by default Given two versions are selected in History When the user clicks Compare Then a side-by-side diff is shown for cards changed, including text, captions, order, and metadata
Pre-Publish Checklist Validation Blocks Publish
Given a user attempts to publish a Card Pack When the pre-publish checklist runs Then the following must pass: 1) Captions present for all cards 2) Media files valid and playable 3) Privacy setting explicitly set 4) Cover selected And any failure item shows a specific error and a deep link to fix it And the Publish action remains disabled until all items pass Given all checklist items pass When the user clicks Publish Then the publish action proceeds and is logged with actor, timestamp, and checklist results
Immutable Published Snapshot with Rollback and Audit Log
Given a Card Pack is published When the publish completes Then an immutable snapshot is created with a unique ID and timestamp that freezes cards, order, captions, cover, and privacy And the public share link resolves to this snapshot And the snapshot cannot be edited; attempting to edit prompts creation of a new draft Given multiple snapshots exist When the Owner opens Snapshot History Then they can view metadata (ID, publisher, timestamp, notes) and compare content between snapshots Given the Owner selects a previous snapshot to restore When they click Rollback Then a new snapshot identical to the selected one is created and set as the current published version And an audit log entry records actor, time, source snapshot ID, and reason
Event Notifications for Mentions, Approvals, and Publishes
Given a user is @mentioned in a comment on a Card Pack they can access When the comment is posted Then they receive an in-app notification within 5 seconds and an email within 60 seconds containing a link to the specific card And duplicate notifications for the same comment are deduplicated within a 10-minute window Given an Editor requests approval to publish a draft When the request is submitted Then all Owners receive an approval request notification with a link to the checklist and draft snapshot Given an Owner approves or rejects the request When the decision is made Then the requester receives a notification with the outcome and any note; approvals only complete if the checklist passes, otherwise the decision action is blocked with failures listed Given a Card Pack is successfully published or rolled back When the action completes Then all collaborators (Owner/Editors/Viewers who follow the pack) receive an in-app notification and email with the snapshot ID and link
Smart Pack Suggestions (AI Assist)
"As an educator, I want AI to propose a pack outline from my lecture so that I can assemble a coherent playlist faster."
Description

Offer AI-powered suggestions to create a Card Pack from a theme prompt or selected source videos by recommending relevant Clip Cards, grouping by topic, proposing titles, and estimating total runtime. Highlight potential duplicates or weak segments and propose an initial ordering optimized for engagement or narrative flow. Allow users to refine with constraints (duration cap, must-include cards) and accept/reject suggestions. Leverage ClipSpark’s transcript analysis, embeddings, and highlight detection; ensure privacy and workspace scoping.

Acceptance Criteria
Prompt-Based Smart Pack Suggestion
Given a signed-in user with an active workspace and permission to view Clip Cards When the user enters a theme prompt and clicks "Generate Suggestions" Then the system returns 0–50 suggested Clip Cards within the current workspace scope, grouped by topic, each with title, start/end timestamps, and a confidence score between 0.00 and 1.00 And the system proposes a Pack title derived from the prompt and top topic And the system displays an estimated total runtime equal to the sum of suggested card durations with an absolute error ≤ 2 seconds And if 0 suggestions are returned, the system displays a clear "No eligible clips" message with next-step guidance (adjust scope or prompt)
Source-Video-Based Smart Pack Suggestion
Given a user selects one or more source videos and clicks "Generate Suggestions" When suggestions are produced Then all suggested Clip Cards originate only from the selected source videos And each suggestion shows a relevance score [0.00–1.00] and can be sorted by this score descending by default And the UI displays the count of suggestions per source video And if no suggestions meet relevance ≥ 0.30, the system returns 0 results with an explanation and suggests widening criteria
Duplicate and Weak Segment Flagging
Given the suggestion set contains semantically similar Clip Cards When any pair has cosine similarity ≥ 0.92 based on embeddings Then both cards are flagged as potential duplicates with a visible badge and are grouped together, recommending the higher-confidence or higher-engagement one And when a Clip Card has highlight score < 0.35 or transcript confidence < 0.85 Then it is flagged as a weak segment with the reason displayed (low highlight score or low transcript confidence) and can be excluded with one click And a summary panel lists counts of duplicates and weak segments detected
Ordering Optimization Modes (Engagement vs Narrative)
Given a set of suggested Clip Cards is available When the user selects "Engagement" ordering Then the list is sorted by engagement score non-increasing, with ties (≤ 0.01 difference) broken by newer source publish date first And when the user selects "Narrative" ordering Then the list is sorted by source video then by start timestamp ascending, and topic groups maintain chronological order without backward time jumps within a group And switching ordering modes updates the visible order within 1 second and displays the active mode label
Constraint Handling: Duration Cap and Must-Include Cards
Given the user sets a duration cap (e.g., 2:00) and marks one or more suggested cards as Must-Include When the user clicks "Refine" Then the system returns a subset that contains all Must-Include cards and has total estimated runtime ≤ cap with absolute error ≤ 2 seconds And if the cap is infeasible because Must-Include cards alone exceed the cap Then the system prevents refinement, shows an error explaining infeasibility, and offers to increase cap or shorten selections And for feasible cases, non-mandatory cards are trimmed by removing the lowest engagement items first while respecting the selected ordering mode
Accept/Reject and Iterative Refinement Workflow
Given suggested Clip Cards are displayed When the user accepts a suggestion Then it is added to the Pack Draft and visually labeled as Accepted And when the user rejects a suggestion Then it is hidden from the current suggestion set and will not reappear on subsequent regenerations with the same prompt and constraints within the same session unless explicitly restored And an Undo option is available for 5 minutes after accept/reject actions And when the user clicks "Apply Suggestions" Then a Card Pack draft is created with the current ordered selections, persisted to the workspace, and a success confirmation is shown
Privacy and Workspace Scoping Enforcement
Given a user belongs to Workspace A and does not have access to Workspace B When the user generates Smart Pack suggestions using any prompt or selected videos Then no suggested Clip Cards originate from Workspace B or any other external tenant And all service calls used to generate suggestions are executed with Workspace A scoping (verified by request metadata) and do not transmit Clip content identifiers from other workspaces And the UI displays the active workspace scope for transparency

HashLock Anchors

Bind every quoted word to its exact audio using per-word cryptographic hashes and positional indices. Survives transcript edits and media re-encodes by re-deriving a canonical fingerprint, delivering court-grade, tamper-evident proof with zero extra workflow.

Requirements

Canonical Audio Fingerprint Derivation
"As a compliance-focused producer, I want a stable audio fingerprint that survives re-encodes so that any later verification proves my transcript words match the original speech."
Description

Derive a deterministic, re-encode-invariant audio fingerprint by canonicalizing input (channel mix-down, normalization, resampling) and extracting fixed-parameter features over sliding windows, then hashing each window with a versioned scheme (e.g., SHA-256). Persist segment-level fingerprints and a rolling root to enable efficient lookups and integrity checks. Run automatically during media ingestion and re-use across transcripts and highlight generation without adding steps to the user workflow. Expose parameter/version metadata to ensure future compatibility and reproducibility.

Acceptance Criteria
Deterministic fingerprint across re-encodes
Given the same source audio content is re-encoded into at least three different formats and bitrates When each variant is ingested Then the canonicalization pipeline produces identical feature streams and per-window hashes And the rolling root hash is identical across all variants And the recorded fingerprint version and parameters are identical across all variants
Automatic fingerprinting during media ingestion
Given a user uploads or imports an audio/video file When ingestion begins Then canonicalization and fingerprint derivation start automatically without any additional user action And no new UI steps are introduced in the upload flow And the ingestion job emits a completion event containing asset ID, fingerprint version, rolling root, and window parameters
Segment-level fingerprints and rolling root persistence
Given fingerprint derivation completes for an asset When persisting results Then per-window hashes with positional indices and time bounds are stored durably and atomically with the asset And a rolling root is computed and stored And retrieving by time range [t0, t1] returns the exact ordered sequence of segments and their hashes And re-deriving the fingerprint and comparing to stored values yields an exact match
Parameter/version metadata exposure and compatibility
Given an asset with derived fingerprints When queried via API and via export Then the response includes algorithm version, sample rate, window length, hop size, channel mix-down strategy, normalization method, hash function, and rolling scheme identifiers And introducing a new algorithm version does not overwrite existing fingerprints; both versions can be addressed independently And re-derivation with the same version reproduces identical hashes
Reuse across transcripts and highlight generation
Given an asset already has stored fingerprints When a transcript is generated, edited, or regenerated, and when highlights are created Then no new fingerprint job is created; the existing fingerprints are reused And anchors resolve using the existing segment indices And edits to the transcript do not alter any stored fingerprints
Lookup and integrity verification API
Given an asset ID and time range When a GET endpoint is called for fingerprints within that range Then the API returns segment hashes, positional indices, and time bounds within the requested range And when a POST verify endpoint is called with a supplied recomputed rolling root or subset proof Then the API returns Pass when matching and Fail when not matching And for a 1-hour asset, the p95 latency for range queries is <= 1.5 seconds in the staging environment
Per-Word Hash & Index Generation
"As a transcript editor, I want every word anchored to the precise audio so that quoted passages are provably authentic."
Description

Bind each transcript word to its exact audio span by aligning ASR word timestamps to the canonical fingerprint and computing a per-word cryptographic hash plus a positional index. Store compact anchor records (word ID, time span, index, hash, version) and expose retrieval via internal services and export endpoints. Ensure low-latency generation and minimal storage overhead to support long-form media at scale.

Acceptance Criteria
Deterministic Per-Word Hash and Index Generation
Given a media file with ASR output containing word-level timestamps When the HashLock Anchors pipeline generates anchors Then an anchor record is created for every ASR word with fields: word_id, start_ms, end_ms, index, hash, version And start_ms and end_ms differ from the ASR timestamps by no more than ±20 ms And index is strictly monotonically increasing per media and starts at 0 And hash equals the SHA-256 of the canonical fingerprint slice for [start_ms, end_ms] concatenated with the version identifier, encoded as lowercase hex And re-running the pipeline on identical inputs produces byte-identical anchor records And the unaligned rate is ≤ 0.1%
Canonical Fingerprint Stability Across Re-Encodes
Given the same audio content re-encoded across at least three codec/bitrate formats When anchors are generated for each variant Then ≥ 99.99% of words have identical hash and index across all variants And per-word start_ms/end_ms drift is ≤ 30 ms relative to baseline And any mismatches are emitted with reason codes and affected word_ids in the job report
Resilience to Transcript Edits
Given a transcript edited for casing, punctuation, and filler-word removal without altering the underlying audio When anchors are regenerated Then for words present in both versions, hash and index values match baseline in ≥ 99.9% of cases And removed words are marked deprecated with a higher version while preserving indices of unaffected words And newly inserted words without aligned audio are flagged as unaligned and do not produce anchors
Compact Anchor Record Storage Overhead
Given anchors are stored for a media item When the serialized size of all anchor records is measured Then average anchor record size is ≤ 96 bytes And total anchor storage overhead is ≤ 1% of the original media file size for items up to 5 hours And the schema includes mandatory fields word_id, start_ms, end_ms, index, hash, version
Low-Latency Generation at Scale
Given a batch of media items up to 4 hours each When anchors are generated on the standard production worker profile Then p95 end-to-end generation time per item is ≤ 1.25x media duration and p99 is ≤ 1.5x And the system sustains ≥ 15 hours of audio processed per wall-clock hour per worker for 1 hour And peak memory usage per worker does not exceed 4 GB per concurrent 2-hour item
Retrieval via Internal Services and Export Endpoints
Given anchors exist for a media item When clients request anchors by word_id list, by time_range, or by index_range Then the service returns records with fields word_id, start_ms, end_ms, index, hash, version ordered by start_ms ascending And pagination via cursor is supported and stable across requests And p95 latency for returning up to 10,000 records is ≤ 200 ms and p99 ≤ 500 ms And export endpoints deliver JSONL and CSV with identical content and a checksum manifest
Tamper-Evidence Verification
Given a media item with intentional content modifications (insertions, deletions, or time-stretching) When anchors are generated and compared against the baseline anchors for the original media Then all modified segments produce different hashes and are reported by the verification endpoint with affected indices and time ranges And false negatives on modified segments are ≤ 0.01% And benign re-encodes do not trigger mismatches beyond the thresholds defined elsewhere
Edit-Resilient Anchor Reconciliation
"As a content curator, I want anchors to survive transcript edits so that I don’t lose proof when refining wording or fixing mistakes."
Description

Maintain anchor integrity through transcript edits by reconciling anchors with an LCS/diff-based algorithm that preserves hashes across insertions, deletions, and replacements. Automatically re-anchor affected spans using nearby stable cues, flag unverifiable words, and present non-blocking warnings. Recompute only impacted regions to keep performance high and keep anchor IDs stable across versions.

Acceptance Criteria
Small Insertion Maintains Anchor Stability
Given a transcript with per-word anchor IDs, hashes, and timestamps, and a defined stability buffer B=50 words When the user inserts 20 words at position i without modifying any surrounding words Then 100% of words with indices < i−B or > i+B retain identical anchor IDs and hashes And timestamps for those unaffected words remain unchanged And the inserted 20 words receive new unique anchor IDs and hashes And the relative order of all anchor positional indices remains strictly increasing
Cross-Paragraph Delete-and-Replace Re-anchors Affected Spans
Given a transcript with anchors and paragraphs and a stability buffer B=50 words When the user deletes 100 consecutive words spanning a paragraph boundary and inserts 80 new words in the same location Then all anchors in the deleted range are retired and not reused And all newly inserted words are assigned new unique anchor IDs and hashes And 100% of words more than B words away from the edited span retain identical anchor IDs and hashes with unchanged timestamps And anchor positional indices remain strictly increasing across the edit
Re-anchoring via Nearby Stable Cues Around Replacements
Given an edit that replaces up to 40 consecutive words and at least two stable cue words exist within ±10 words on both sides of the span When reconciliation runs using an LCS/diff-based algorithm Then ≥98% of unchanged words within and adjacent to the span are correctly re-attached to their original audio within ±100 ms And false-positive re-anchors (mismatching to a different occurrence of the same token) are ≤3% And the reconciliation report enumerates re-anchored words with old→new positional indices
Non-Blocking Unverifiable Word Warnings
Given reconciliation identifies unverifiable words (no matching hash after edit) in any span When the user saves the edited transcript Then a warning banner with the count of unverifiable words appears within 500 ms in the editor And exports (captions, summaries, highlights) remain enabled and complete without error And the reconciliation report includes a machine-readable list of unverifiable word IDs and locations And no preserved or correctly re-anchored word is marked unverifiable (0% false positives in test fixtures)
Incremental Recompute Limits Scope and Time
Given a transcript of 10,000 words with N disjoint edited spans totaling E words and a stability buffer B=50 words When reconciliation runs Then the number of re-hashed anchors is ≤ E + (2×B×N) And no anchors outside the union of all [span−B, span+B] windows are re-hashed And reconciliation completes in ≤1.5 seconds when E ≤5% of total words on the baseline test dataset And CPU time is ≤30% of a full recompute on the same input
Deterministic Output and Stable Anchor IDs Across Versions
Given the same baseline transcript, audio, and identical ordered edits applied twice When reconciliation runs on both runs Then the resulting anchor IDs, hashes, timestamps, and unverifiable sets are bit-identical And any word that persists across versions maintains the same anchor ID as in the baseline And the version-to-version diff API returns stable mappings for preserved, re-anchored, retired, and newly created anchors
Tamper-Evidence Verification UI & API
"As a reviewer, I want to verify quoted segments instantly so that I can trust and share proofs with stakeholders."
Description

Provide a one-click verification panel and a public API that validate selected words, quotes, or ranges against the media by re-deriving the canonical fingerprint and comparing stored hashes. Return a clear pass/fail report with mismatch locations and tolerances, and expose machine-readable results for third-party tooling. Include a lightweight, open verifier and deterministic output to support independent, court-ready checks without requiring ClipSpark accounts.

Acceptance Criteria
UI One-Click Verification of Selected Text
Given a transcript is displayed with a corresponding media file and per-word anchors are present When the user highlights a quote or selects a word-index range and clicks "Verify" Then the system re-derives the canonical fingerprint from the media bytes for the selected range using the configured HashLock algorithm version And compares the derived per-word hashes and positional indices against the stored anchors without trusting any cached verification And shows a result banner with "Pass" or "Fail", the count of words verified, start/end word indices, algorithm version, tolerance used, and elapsed time And provides a downloadable verification report in JSON containing verification_id, timestamp (UTC ISO-8601), media_sha256, transcript_revision_id, selected_range, result, mismatches (if any), tolerance_ms, algorithm_version, and canonical_fingerprint And disables the Verify action while computation is running and re-enables it on completion And completes verification of a ≤30-second selection from a ≤60-minute media file within 3 seconds at p95 on reference hardware
Range Verification with Mismatch Locations and Tolerance
Given a selection includes at least one altered word relative to stored anchors When the user runs verification with time_drift_tolerance_ms set to 20 Then the result is "Fail" And the report lists each mismatch with fields: word_index, char_offset, expected_hash, observed_hash, start_timecode, end_timecode And timing differences ≤ 20 ms without hash differences are not reported as mismatches And the UI highlights mismatched words inline and provides a link to jump to each mismatch in the media And the API response includes mismatch_count equal to the number of mismatched words and a non-empty mismatches array
Public API Verification with Deterministic, Machine-Readable Output
Given a client POSTs to /v1/verify with a JSON body containing media_locator (https URL or sha256+fetch_token), transcript_id or embedded_anchors, selection (word_indices or quote_text), and tolerance_ms When the request is valid and the media is retrievable Then the API responds 200 application/json with a body that validates against the published JSON Schema id "https://clipspark.dev/schemas/verify-result.v1.json" and version "1.0.0" And the response includes fields: verification_id, result ("Pass"|"Fail"), mismatch_count, mismatches[], selected_range, media_sha256, transcript_revision_id, tolerance_ms, algorithm_version, canonical_fingerprint, generated_at, response_hash And repeated requests with identical inputs on the same algorithm_version return byte-identical JSON (including field order and whitespace) and the same response_hash And invalid inputs return 400 with a machine-readable error code and message; unverifiable media (unreachable or unsupported) return 422 with a specific code And no ClipSpark account or API key is required to call the endpoint And 95th-percentile latency for verifying a ≤30-second selection is ≤ 2 seconds under a concurrency of 20 requests
Open, Accountless Verifier Availability and Reproducibility
Given the open verifier CLI is installed from the public repository without authentication When the user runs "clipspark-verify --media path/to/media --anchors path/to/anchors.json --range 120-165 --tolerance-ms 20" Then the CLI outputs a JSON result that is byte-identical to the API response for the same inputs (including response_hash) And the repository includes a reproducible build script that produces a binary whose sha256 matches the published release checksum And the verifier operates fully offline given local media and anchors and exits with code 0 on Pass, 2 on Fail, and 1 on error And the packaged binary size is ≤ 15 MB and peak memory usage ≤ 150 MB when verifying a ≤30-second selection
Verification Robustness to Transcript Edits and Media Re-encodes
Given the transcript has non-semantic edits (whitespace, punctuation, casing) and the media has been re-encoded (codec/bitrate/container changed) without altering audio content When verifying an unchanged quote or range against the re-encoded media and edited transcript Then the result is "Pass" for all unchanged words with 0 mismatches reported And the tolerance_ms accounts for alignment drift up to 20 ms without producing mismatches And if a word's audio content is altered or replaced, that word is reported as a mismatch with correct indices and timecodes And the report includes the media_sha256 of the verified media and the transcript_revision_id reflecting the edited transcript
Error Handling and Clear Failure Reporting
Given an unsupported codec, corrupt media, out-of-range selection, or ambiguous quote is submitted When verification is attempted via UI or API Then the system returns a non-200 (API) or an error banner (UI) with a specific error code: V001 (unsupported_media), V002 (corrupt_media), V003 (range_out_of_bounds), V004 (ambiguous_quote), V005 (anchor_missing) And the error response includes remediation guidance and a correlation_id for support And validation errors are detected client-side where possible and block submission with inline messages And processing stops without partial results and the operation is logged with no sensitive media bytes persisted beyond processing
Cross-Encode Robustness & Codec Support
"As a podcaster, I want anchors to verify after platform re-encodes so that my proofs hold wherever I publish."
Description

Guarantee consistent anchoring across common codecs, bitrates, and sample rates by standardizing canonicalization and validating against a matrix of audio/video formats (e.g., MP4/AAC, MOV, WAV, MP3, MKV/Opus). Define acceptable timing tolerances, implement fallback strategies for edge cases, and ship an automated regression suite to prevent drift across encoder updates.

Acceptance Criteria
Codec Matrix Hash Equivalence
Given a 60-minute baseline corpus with per-word anchors derived from original WAV/PCM When the same content is re-encoded into MP4/AAC (CBR 128 kbps, 44.1 kHz), MOV/AAC (VBR 192 kbps, 48 kHz), MP3 (CBR 128 kbps, 44.1 kHz), MKV/Opus (VBR ~96 kbps, 48 kHz), and WAV/PCM (16-bit, 48 kHz) Then the canonicalization pipeline produces per-word cryptographic hashes that are 100% identical to the baseline for all words And no missing or extra anchors are produced And processing completes without manual intervention
Timing Tolerance Across Re-encodes
Given a baseline set of per-word timestamps from the canonicalized waveform When anchors are re-derived from each supported codec/bitrate/sample-rate combination Then the absolute timestamp delta per word is ≤ 20 ms at the 95th percentile and ≤ 40 ms at the maximum across the corpus And word order is preserved with no swaps or merges And any anchor exceeding 40 ms delta is flagged and fails the run
Bitrate and Sample-Rate Robustness
Given source audio S and a baseline per-word hash/timestamp set When S is encoded at sample rates {32 kHz, 44.1 kHz, 48 kHz} and bitrates {64, 96, 128, 192, 320 kbps} for AAC, MP3, and Opus Then per-word hashes match the baseline for ≥ 99.99% of words per file before fallback And the remaining ≤ 0.01% words are recovered via secondary alignment to reach 100% match And final timestamp tolerance satisfies p95 ≤ 20 ms and max ≤ 40 ms
Transmux Integrity (No Audio Re-encode)
Given an input file with audio track A and baseline anchors When the container is changed without audio transcoding (e.g., MP4→MKV, MOV→MP4) and anchors are re-derived Then all per-word hashes and timestamps are bit-for-bit identical to the baseline outputs And the number of anchors equals the baseline count exactly
Fallback Strategy on Decode or Drift
Given an input that fails decoding or exhibits > 0.01% hash mismatches or any timestamp delta > 40 ms When processing executes Then the system automatically applies fallback steps in order: alternative resampler, band-limited canonicalization, dynamic time-warp alignment, and segment-level anchoring And after fallback, per-word hash mismatches are 0 and timing tolerances are met (p95 ≤ 20 ms, max ≤ 40 ms) And if recovery fails, the file is marked Non-Verifiable with a machine-readable reason and surfaced via API/UI with HTTP 422 and error code HASHLOCK_UNVERIFIABLE
Automated Regression and Encoder Drift Guard
Given a pinned encoder matrix (ffmpeg, libmp3lame, aac, libopus) and a 10+ hour golden corpus across domains When CI runs on each commit and on a weekly schedule Then any increase above 0% in hash mismatch rate or any timing p95 > 20 ms fails the build And the suite emits a signed report with per-format pass/fail, deltas, and artifacts for triage And dependency updates are blocked unless the suite passes or an explicit, signed baseline refresh is committed
Proof Packaging & Export
"As a legal coordinator, I want downloadable proof files tied to my captions so that third parties can verify authenticity without accessing our workspace."
Description

Package anchors into portable proofs that travel with media and transcripts, including a signed JSON proof bundle and optional cues embedded in caption files (WebVTT/SRT) and MP4 metadata. Include version, media identifiers, hash scheme, and minimal data for selective verification. Enable exports from project, clip, or quote views and support import for offline verification tools.

Acceptance Criteria
Project-Level Export of Signed JSON Proof Bundle
Given a project containing at least one processed media file with generated anchors and transcript When the user selects Export > Proof Bundle from the Project view Then a .proof.json file is generated and downloaded without error And the bundle validates against the published clipspark-proof-bundle JSON Schema v1 And the bundle includes fields: version, hashScheme, mediaIdentifiers (including mediaContentHash and mediaDurationMs), anchors (minimal data for selective verification), and signature And no full transcript text is included beyond what is minimally required for selective verification
Clip- and Quote-Level Scoped Export
Given the user is viewing a specific clip or a selected quote When the user exports a proof bundle from that view Then the bundle contains only anchors whose time ranges fall within the selected clip/quote And the bundle includes the parent project and mediaIdentifiers to disambiguate the source media And the bundle signature is present and validates And anchors outside the selected range are excluded
Caption File Embedding of Anchor Cues (WebVTT/SRT)
Given a transcript with anchors exists for a media file When the user exports captions (WebVTT or SRT) with "Embed Proof Cues" enabled Then the caption file remains valid per its respective specification when run through a standard validator And the file includes namespaced, non-rendered cues or comments carrying per-anchor indices and hashes (e.g., X-CLIPSPARK-ANCHOR) And standard media players display captions unchanged (no visible proof artifacts) And the embedded cues are parsable by the reference verifier to reconstruct anchor mappings
MP4 Metadata Embedding of Proof Reference and Cues
Given a processed MP4 with anchors is ready for export When the user exports the MP4 with "Embed Proof" enabled Then the MP4 contains a metadata entry with the proof bundle reference (bundle hash and version) under a namespaced key (e.g., com.clipspark.proof.reference) And, if selected, a timed metadata track contains anchor cue data aligned to media timestamps And the exported MP4 remains playable in standard players without errors And ffprobe or exiftool inspection reveals the expected metadata entries
Selective Verification Using Minimal Proof Data
Given an exported proof bundle, the corresponding media file, and a target quote time range When the offline reference verifier is run without network access Then the verifier re-derives the canonical fingerprint for the target range and validates the included anchors using only the bundle's minimal data And the verifier outputs a VERIFIED result with anchor indices and offsets when inputs are authentic And if either the media or bundle is altered, the verifier outputs FAILED with a clear reason code
Versioning and Schema Compatibility
Given a proof bundle produced with schema version v1 When it is processed by a verifier that supports versions v1 through vNext Then the bundle is accepted and validated without warnings And if the bundle's version is unsupported, the verifier returns an UNSUPPORTED_VERSION error without crashing And the export UI displays the schema version and hash scheme recorded in the bundle
One-Click Export Availability Across Views
Given the user is in Project, Clip, or Quote view When the user initiates a proof export with default options Then the export completes with no more than one confirmation dialog and no additional data entry required And the same default export options (bundle only; optional captions/MP4 embedding toggles) are available consistently across all three views And the resulting artifacts (bundle and any selected embeddings) are stored/downloaded to the configured export location
Audit Trail & Versioning
"As a compliance officer, I want an auditable history of anchors and parameters so that I can demonstrate integrity over time."
Description

Record a tamper-evident audit trail of fingerprint parameters, anchor creation events, transcript edit history, and verification outcomes. Version the hash scheme and canonicalization parameters and attach them to each proof. Provide time-stamped logs and a human-readable report to support chain-of-custody needs and long-term reproducibility.

Acceptance Criteria
Hash-Chained, Append-Only Event Log
- Given audit logging is enabled, When an anchor is created, updated, or deleted, Then an event is appended containing eventType, anchorId, actorId, UTC timestamp (ISO 8601 with millisecond precision), previousEventHash, and a new logHeadHash computed with SHA-256. - Given any event record is modified or removed, When verifying the log chain, Then verification fails and returns the index of the first broken link. - Given 10,000 existing events, When appending a new event on reference hardware (8 vCPU, 16 GB RAM), Then the append and hash update complete in <= 50 ms and the logHeadHash changes.
Versioned Hash Scheme Attribution
- Given a proof is generated for a quote, When the proof is inspected, Then it includes fields: hashSchemeVersion, canonicalizationVersion, algorithm, audioParams (sampleRateHz, channelLayout, normalization), and softwareBuildId. - Given the global hash scheme is upgraded from v1 to v2, When generating new proofs, Then proofs embed v2 while existing v1 proofs remain verifiable using their embedded versions. - Given a v1 proof, When verified in an environment supporting v1 and v2, Then the system selects v1 and reproduces baseline digest values byte-for-byte.
Transcript Edit History with Diffs
- Given a user edits the transcript, When saving, Then an audit event records: editType (insert/delete/replace), beforeText, afterText, affectedIndices (start,end), actorId, reason, UTC timestamp, and impacted anchorIds. - Given an edit changes anchoring, When re-deriving fingerprints, Then a reDerivation event links from oldFingerprintIds to newFingerprintIds with hashSchemeVersion and canonicalizationVersion; no prior event is mutated. - Given a revert to a previous transcript version, When saved, Then a revert event references the prior versionId and all intermediate events remain in the chain.
Verification Outcome Logging & Reproducibility
- Given a proof and media, When verify() runs, Then the audit trail logs: verificationId, proofId, mediaChecksum (SHA-256), mediaDuration, timeRange, configId, softwareBuildId, UTC timestamp, and outcome (Pass/Fail) with confidence [0..1]. - Given the same inputs and build, When verify() is re-run, Then outcome, per-word match map, and final digest are identical and the new verificationId is linked as rerunOf the original. - Given a media mismatch, When verify() fails, Then the event includes expectedChecksum vs actualChecksum and failureReason = "MediaChecksumMismatch".
Chain-of-Custody Report Generation
- Given a project with anchors and edits, When generating a chain-of-custody report, Then the system outputs HTML and PDF containing case metadata, event counts, a timeline with UTC timestamps, current logHeadHash, and a reportChecksum (SHA-256). - Given any log mutation, When regenerating the report, Then the reportChecksum differs and validate(report) flags "AuditLogTampered". - Given signing keys are configured, When the report is generated, Then it is CMS/PKCS#7 signed and validates against the published public key fingerprint.
Audit Log Export/Import & Retention Policy
- Given an export is requested for a date range, When executed, Then the system writes a signed JSONL file with schemaVersion, firstEventIndex, lastEventIndex, and final logHeadHash; a file checksum is returned. - Given an exported file, When importing into a clean instance, Then the system verifies signature, checksum, and hash chain and reconstructs the same logHeadHash; any discrepancy aborts import with an error. - Given a retention policy of N years, When events exceed N years, Then they are archived to WORM storage and an archive event records archiveLocation, archiveChecksum, and retentionRuleId; no deletion or mutation of existing hash links occurs.

Context Halo

Auto-attach a configurable buffer (e.g., 10–30 seconds) before and after each quote and lock it cryptographically. Reviewers can expand the halo with one click to hear surrounding audio, reducing cherry-pick disputes and speeding approvals.

Requirements

Halo Configuration Controls
"As a content owner, I want to set default halo durations so that every quote includes sufficient context without manual adjustments."
Description

Provide global, workspace, and project-level settings to define default pre- and post-context halo durations with a supported range of 5–60 seconds and 1-second granularity. Allow per-quote override during creation and editing, with guardrails preventing halos that exceed media boundaries. Persist settings to user preferences and expose them via API so automation and presets can apply consistent halos across ingest pipelines. Include toggles to enable halos by default for highlights, captions, and summaries, and to include or exclude halos in exports. Changes to defaults do not retroactively alter existing quotes unless explicitly reprocessed. Display the current effective halo configuration in the UI for transparency.

Acceptance Criteria
Multi-Level Defaults and Effective Configuration Display
Given global, workspace, and project default halo durations must be configurable within 5–60 seconds at 1-second increments When a user sets global defaults to 10s pre and 20s post Then the values save and persist across sessions When a workspace default is set to 12s pre and 22s post Then projects in that workspace inherit 12s/22s unless overridden at project level When a project default is set to 15s pre and 25s post Then quotes in that project use 15s/25s by default When a user attempts to set 4s or 61s, or a non-integer like 12.5s Then validation prevents saving and shows a clear error Then the UI displays the effective pre/post halo values and indicates their source (project > workspace > global) in the current context
Per-Quote Halo Override at Creation and Edit
Given a new quote is created within a project with effective defaults of 15s pre and 25s post Then the quote editor pre-fills 15s/25s When the user overrides to 18s pre and 20s post (within 5–60, integer seconds) Then the quote saves with 18s/20s and playback/export use these values When the user enters 61s or 3s or 10.5s Then the editor blocks save and shows validation messaging When the user clears the override fields Then the quote reverts to the current effective defaults When editing an existing quote with an override Then changes save and are reflected immediately in playback and subsequent exports
Media Boundary Guardrails
Given a media file of 5:00 and a quote starting at 00:08 with end at 00:20 and default pre/post halos of 15s/15s When pre-halo would extend before 00:00 or post-halo beyond 05:00 Then the system clamps halos to media boundaries (pre to 8s, post unchanged) without allowing negative or overflow timestamps Then a non-blocking notice informs the user that halos were adjusted to fit media boundaries When saving or exporting the quote Then the persisted/exported timestamps reflect the clamped halo durations accurately
Halo Settings API for Automation and Ingest
Given an authenticated client requests halo configuration via API When calling GET for global/workspace/project settings Then the response includes pre/post durations, 5–60 range enforcement, 1s granularity, and per-type default toggles When calling PUT/PATCH to update settings with values in range and integer seconds Then the API accepts and persists changes; out-of-range or non-integer values return 400 with validation details When creating/updating a quote via API with a per-quote override Then the override is stored and used; invalid values are rejected with 400 When ingesting media without specifying halo settings Then the pipeline applies the effective defaults consistently across runs When ingest specifies a preset or explicit durations Then those are applied consistently, subject to the same validations
Default Halo Toggles by Output Type
Given default halo toggles exist for highlights, captions, and summaries at global/workspace/project levels When toggles are enabled for a type in the current context Then newly generated items of that type automatically include halos using the effective pre/post durations When toggles are disabled for a type Then newly generated items of that type do not apply halos unless a per-quote override is explicitly set Then toggles persist across sessions and are retrievable/settable via API
Export Include/Exclude Halo Controls
Given a user initiates an export for selected quotes When the user selects Include Halos Then the exported media and caption ranges extend by the configured pre/post halo durations (subject to clamping) and the output duration increases accordingly When the user selects Exclude Halos Then the export contains only the core quote without halo buffers When the same export is initiated via API with includeHalos=true/false Then the exported assets match the selected behavior Then export metadata indicates whether halos were included
Non-Retroactive Defaults and Explicit Reprocessing
Given existing quotes created under previous defaults When an admin changes default halo durations or toggles at any level Then existing quotes remain unchanged in playback and export When a user explicitly triggers reprocess for a quote or project Then quotes without per-quote overrides update to the new effective defaults Then quotes with per-quote overrides retain their overrides unless the user chooses Reset to Defaults during reprocess Then audit/history records indicate the reprocess action and resulting halo values
Auto Halo Attachment Engine
"As a producer, I want halos auto-attached when quotes are generated so that reviewers always have surrounding audio to assess context."
Description

Automatically attach the configured halo to every detected quote, highlight, and caption segment at generation time. Compute normalized start and end timestamps, clamped to media bounds, and store the halo as immutable metadata linked to the source media ID, transcript segment IDs, and configuration version. Ensure that waveform, transcript, and player components all reference the same halo metadata so playback, rendering, and exports remain consistent. Provide a reattach operation when quotes are regenerated or when users elect to apply updated defaults, with background jobs to handle batch updates at scale.

Acceptance Criteria
Auto-attach halos during segment generation
Given a media asset of duration D and halo defaults pre=P seconds, post=Q seconds And transcript detection yields segments (quotes/highlights/captions) with base times s..e When the Auto Halo Attachment Engine runs at generation time Then for each segment it persists a halo with: - start_ts = max(0, s − P) and end_ts = min(D, e + Q) - timestamps normalized to the media’s timeline (seconds, precision >= 0.001s) - links: source_media_id, transcript_segment_id(s), configuration_version, pre_buffer_s=P, post_buffer_s=Q - created_at and created_by identifiers And clamping is verified for segments near media start/end And halos exist before any UI render or export endpoint responds for that media item
Cryptographic halo locking and immutability
Given a stored halo record with a signature S computed over its canonical metadata payload When any attempt is made to mutate core fields (start_ts, end_ts, buffers, links, configuration_version) Then the system rejects in-place updates and requires creating a new halo version with a new id and signature And recomputing the signature for stored halos matches S; otherwise the record is rejected and flagged And previous halo versions remain retrievable and auditable
Unified halo metadata across UI, playback, and exports
Given a segment referencing halo_id=H When the waveform view, transcript view, in-app player, and export services render the segment Then each retrieves halo H and uses [start_ts, end_ts] for: - playback in/out points - waveform highlight extents - transcript context shading - exported clip trim points and caption timecodes And the same halo_id H appears in telemetry and export manifests And one-click "Expand halo" playback does not mutate halo metadata or create a new version
User-initiated reattach with updated defaults
Given halo defaults change from version v1(P1,Q1) to v2(P2,Q2) And a user selects "Apply updated defaults" for a media item with N segments When reattach is triggered Then a background job creates new halos using v2 for all N segments, linking to the same source_media_id and transcript_segment_ids, and setting configuration_version=v2 And each segment’s active_halo_id is switched atomically to the new version And prior halos remain immutable and are marked superseded but auditable And the operation is idempotent on repeated invocation And job progress (queued, processed, failed), duration, and summary counts are visible to the user
Reattach on quote regeneration
Given quotes are regenerated due to transcript changes producing a new set of segment_ids When regeneration completes Then halos are created for all new/changed segments per the current defaults and linked to the new segment_ids And unchanged segments retain their existing halo_id and version And halos orphaned by deleted segments are archived and excluded from active references And UI views and exports reflect the updated mappings with no stale or duplicate references
Scalable batch reattach with resilience
Given an organization-wide reattach runs over >=500 media and >=100,000 segments When the batch job executes Then it processes segments in parallel with rate limiting, supports checkpointing and resume-on-failure, and guarantees at-least-once creation with at-most-once activation per segment And retries transient failures up to 3 times with exponential backoff And achieves >=99.9% success rate, emitting a report of failed segment_ids for manual retry And exposes metrics for throughput, latency, error rate, and completion status
One-Click Halo Expansion UI
"As a reviewer, I want to expand the halo with one click so that I can hear the surrounding conversation and approve faster."
Description

Add a prominent control in the review player and transcript view to expand playback to include the pre/post halo with a single click, without altering the underlying quote timestamps. Support incremental expansion in configurable steps (e.g., +5s) up to a safe maximum, plus keyboard shortcuts and screen reader labels. Visually indicate the halo on the timeline and transcript with shading and boundary markers. Keep audio and transcript scrolling synchronized when expanded. Prefetch halo audio and text to keep expansion latency under 250 ms on broadband connections and gracefully degrade on slow networks with a loading indicator.

Acceptance Criteria
One-click halo expansion in player and transcript
Given a reviewer is viewing a quote in the review player or transcript view and a pre/post halo duration is configured When the reviewer activates the Expand Halo control Then playback immediately extends to include the configured pre/post halo for the current quote And the quote’s stored start and end timestamps remain unchanged in memory and persistent storage And the UI clearly indicates that Halo Expansion is active for the current quote
Incremental halo expansion respects configurable maximum
Given halo expansion is active and the step size is configured (e.g., 5s) with a maximum per side (e.g., 30s) When the reviewer triggers Increment Halo (via button or keyboard shortcut) Then the halo increases by exactly one step on both sides without exceeding the configured maximum per side And upon reaching the maximum, the increment control is disabled and an accessible hint indicates the limit is reached And the quote’s stored start and end timestamps remain unchanged
Halo visualization on timeline and transcript with accessible boundaries
Given halo expansion is active Then the media timeline displays shaded pre- and post-halo regions with boundary markers labeled with relative offsets (e.g., -10s, +10s) meeting WCAG 2.1 AA contrast (≥ 4.5:1) And the transcript view shades the corresponding halo lines/words and shows boundary markers aligned to the same offsets within 100 ms of playback position And boundary markers visually align with the audio positions within ±100 ms
Keyboard shortcuts and screen reader support for halo expansion
Given the review UI is focused When the reviewer presses the default shortcut Alt+Shift+Right Arrow Then the halo expands by one configured step for the current quote (respecting max) And the Expand Halo button has an accessible name and description announced by screen readers (e.g., aria-label and aria-description) And changes in expansion amount are announced via a polite live region (e.g., “Halo expanded to 15s each side”) And all controls are reachable in a logical tab order without traps
Synchronized audio and transcript scrolling during halo playback
Given halo expansion is active and playback is running at 0.5x, 1x, 1.5x, or 2x When playback crosses into or out of halo regions Then the transcript auto-scrolls to keep the current line in view and word highlighting stays synchronized within 200 ms of audio And no visible desynchronization persists for longer than 1 second under any supported speed
Prefetch ensures sub-250 ms expansion latency; graceful degradation on slow networks
Given a broadband connection of ≥ 25 Mbps down and halo assets are prefetched upon quote selection or control hover/focus When the reviewer activates halo expansion Then the time from click to audible playback of halo audio and visible transcript expansion is ≤ 250 ms at the 95th percentile over 50 trials And on slower connections (< 5 Mbps), a loading indicator appears within 100 ms of click and remains until halo assets are ready, without freezing the UI thread
Quote timestamps remain unchanged in storage and exports
Given halo expansion has been used during review When the reviewer copies timestamps, exports a clip, or generates a share link Then the original quote start and end timestamps are used (not the expanded playback range) And any displayed timestamps in export dialogs match the stored quote boundaries exactly
Cryptographic Halo Seal & Verification
"As a compliance officer, I want halos to be cryptographically sealed so that I can verify no context was removed or altered."
Description

Generate a tamper-evident seal for each quote that binds the source media identifier, quote start/end timestamps, halo durations, transcript snippet hash, and configuration version. Use SHA-256 for hashing and Ed25519 for signatures with server-held private keys. Store the signature alongside the quote metadata and expose a verification endpoint and client-side verifier to confirm integrity on load and before approval or export. Display a clear verification badge and error states if verification fails. Prevent editing sealed fields; edits require creating a new sealed version with lineage to the prior version.

Acceptance Criteria
Seal Generation on Quote Creation
Given a new quote is created with source_media_id, start_timestamp, end_timestamp, halo_before_seconds, halo_after_seconds, transcript_snippet, and configuration_version And transcript_snippet_hash is computed using SHA-256 over the UTF-8 transcript_snippet When the quote is saved Then the service builds a canonical JSON of {source_media_id, start_timestamp, end_timestamp, halo_before_seconds, halo_after_seconds, transcript_snippet_hash, configuration_version} And computes a SHA-256 hash of that canonical JSON And signs the hash using Ed25519 with a server-held private key And stores the base64-encoded signature and key_id alongside the quote metadata And the signed fields are persisted as immutable
Verification API Returns Integrity Status
Given a POST to /verify with the quote metadata, signature, and key_id When the signature verifies against the public key for key_id and matches the recomputed hash of the canonical JSON Then respond 200 with {verified: true, code: "ok"} When any signed field is altered or the signature does not verify Then respond 200 with {verified: false, code: "signature_mismatch"} When inputs are missing or malformed Then respond 400 with {verified: false, code: "invalid_request"} And P95 latency for successful verification is ≤ 200 ms for payloads ≤ 1 KB
Client-Side Auto-Verification and Badging
Given a sealed quote loads in the review UI When the UI initializes Then the client verifier recomputes the hash and verifies the Ed25519 signature using the published public key for key_id And displays a green "Verified" badge if valid When the user initiates Approve or Export Then verification is performed again immediately prior to action And if verification fails, the action is blocked and a red "Verification failed" banner with error code is shown When verification cannot run (e.g., offline or missing public key) Then show a gray "Unverified" badge and provide a Retry option; Approve/Export remains disabled until verified
Editing Restrictions and Versioned Reseal
Given a sealed quote exists When a user attempts to edit any sealed field (source_media_id, start_timestamp, end_timestamp, halo_before_seconds, halo_after_seconds, transcript_snippet_hash, configuration_version) Then the UI and API reject in-place edits and prompt to create a new version When the user confirms creating a new version Then a new version is created with parent_version_id referencing the prior version And a new seal (hash + Ed25519 signature) is generated over the updated canonical JSON And the prior version remains immutable and visible in version history
One-Click Halo Expansion Creates New Sealed Version
Given a reviewer clicks "Expand Halo" by N seconds When halo_before_seconds and/or halo_after_seconds are increased Then the system creates a new quote version with updated halo durations And generates a new seal binding the same source_media_id, start_timestamp, end_timestamp, transcript_snippet_hash, configuration_version, and the updated halo durations And links the new version to the prior version via parent_version_id And displays a green "Verified" badge if the new seal verifies
Tamper and Error State Display
Given any sealed field or the stored signature is altered after sealing When the quote is loaded or verification is requested Then verification fails And the UI shows a red "Verification failed" badge with an error code (e.g., "signature_mismatch", "unsupported_key", "data_missing") And Approve/Export actions are disabled until a valid newly sealed version exists
Server-Held Key Use and Rotation
Given signing operations are performed on the server Then Ed25519 private keys remain server-held and are never exposed to clients or logs And each signature includes a key_id that maps to a published public key for verification When key rotation occurs and a new key_id is active Then existing quotes continue to verify with their original key_id/public key And newly sealed quotes use the new key_id When verification receives an unknown key_id Then it returns {verified: false, code: "unsupported_key"}
Review Audit Trail
"As an editor lead, I want an audit trail of halo interactions so that I can resolve disputes about cherry-picking with evidence."
Description

Record an immutable audit log of review activities related to halos, including expansions, approvals, rejections, comments, re-seals, and reattachments. Capture user ID, timestamp, IP, client version, and the verification result at the time of action. Surface the audit trail in the review UI and make it exportable as JSON/CSV for dispute resolution. Support retention policies and access controls so only authorized roles can view or export logs.

Acceptance Criteria
Audit Log Entry Creation for Halo Review Actions
Given a reviewer performs any of the following actions on a halo: expand, approve, reject, comment, reseal, or reattach When the action is submitted and acknowledged by the server Then exactly one audit entry is appended with fields: action_type, halo_id, recording_id, user_id, timestamp_utc (ISO 8601 with milliseconds), ip_address, client_version, verification_result, request_id, and entry_id (monotonic per recording) And timestamp_utc reflects server receipt time within ±200 ms of system clock And verification_result is one of: seal-valid, seal-invalid, unverifiable; if not seal-valid, a reason_code is populated
Immutable Hash Chain and Tamper Detection
Given an audit log with N entries exists for a recording When a new entry is appended Then the entry includes prev_hash (hash of prior canonical entry) and content_hash (SHA-256 of canonicalized fields) and the chain_head is updated And the /audit/verify endpoint returns Pass for unmodified logs and Fail if any prior entry is altered, removed, or re-ordered, identifying the first offending index And any attempt to update or delete an existing audit entry returns 403 and results in no change to chain_head
Review UI Surfaces Audit Trail
Given a reviewer opens the review UI for a recording When the Audit tab is viewed Then entries appear in reverse chronological order with columns: Action, User, Timestamp (local with UTC on hover), IP, Client Version, Verification Result, Details And the list supports filter by action type, user, and date range; and paginates or infinite-scrolls with initial render of 100 entries in ≤1.0 s on a 50th percentile network And clicking an entry shows structured details including halo start/end timestamps, expansion deltas, and any comment text
Export Audit Trail to JSON and CSV
Given a user with AuditLog.Export permission and a filtered set of audit entries When Export as JSON is selected Then a UTF-8 JSON file is downloaded or streamed containing all matching entries in the same order, with top-level metadata: recording_id, exported_at_utc, applied_filters, total_count, chain_head_hash When Export as CSV is selected Then a RFC 4180-compliant CSV with a header row is produced; timestamps are UTC ISO 8601; fields are properly quoted; newlines preserved And exports of >50,000 entries run as an async job that completes within 2 minutes for 100,000 entries, provides a progress indicator, and yields a signed download URL
Role-Based Access Control for Audit Logs
Given a user without AuditLog.View permission When they attempt to access the audit trail UI or API Then the system returns 403 and no audit data is disclosed Given a user with AuditLog.View but without AuditLog.Export When they attempt an export Then the export controls are disabled in the UI and the API returns 403 And every access attempt (granted or denied) is recorded as an audit entry with action_type=access_granted or access_denied without exposing protected content
Retention Policy Enforcement and Legal Hold
Given a workspace retention_days=N and no legal hold on a recording When an audit entry ages beyond N days Then the entry is purged and a retention_purge audit marker is appended capturing the purged range and re-anchoring hash or tombstone Given a recording under legal hold When the retention job runs Then no entries for that recording are purged and a retention_skipped_legal_hold marker is appended And UI and exports exclude purged entries while the /audit/verify endpoint returns Pass using tombstone markers for integrity
Atomicity, Idempotency, and Ordering Guarantees
Given a review action is submitted When the audit append cannot be persisted Then the review action is rolled back and an error is returned; no partial audit entry exists Given the same request_id is retried within 24 hours When processed by the server Then at most one audit entry exists for that request_id and its entry_id/order is unchanged And all entries for a recording are strictly ordered by server-assigned sequence; concurrent actions are ordered by commit time
Shareable Verification Links
"As an external reviewer, I want a secure link that verifies the clip and its halo so that I can trust the context without logging in."
Description

Create secure, expiring share links for highlights that embed or reference the halo and its cryptographic seal. Public viewers can play the clip, expand the halo, and see verification status, but cannot shrink or edit the halo. Respect existing access controls, watermarks, and domain restrictions. Track link views and verification outcomes for audit. Provide an embeddable widget that preserves verification indicators when hosted externally.

Acceptance Criteria
Public Viewer Plays Verifiable Highlight via Share Link
Given an active share link to a highlight with a configured halo and a public viewer When the link is opened in a supported browser Then the player renders the highlight with the halo visually indicated, no trim/edit controls are available, and playback is allowed without authentication Given the player has loaded When the viewer presses Play Then playback begins within 2 seconds on a 5 Mbps connection and the verification badge (Verified/Unverified/Unknown/Expired) is visible throughout playback
Halo Expansion Allowed, Shrink and Edit Prohibited
Given a share link with a 20s halo When the viewer clicks Expand Halo Then the audible context extends by the configured step (e.g., +10s) up to the maximum allowed and the original sealed segment remains unchanged Given the viewer attempts to shrink the halo or edit the clip (via UI or URL parameters) When the action is submitted Then the halo duration remains unchanged, UI shows read-only controls, and tampering via URL is rejected with a 400 response Given the halo has been expanded When verification status is displayed Then the UI clearly indicates the sealed segment versus expanded (unsealed) context
Expiring Link Enforcement and Owner Revocation
Given a share link with an expiry timestamp T When the current time is after T Then opening the link shows an Expired state, returns HTTP 410 (or 404 if configured), playback is disabled, and the verification badge shows Expired Given the owner revokes the link before T When the link is opened Then a Revoked state is shown, HTTP 403 is returned, and playback is disabled Given a link is valid and within 24 hours of expiry When the viewer opens the link Then the UI displays a visible "Expires in <time>" indicator
Cryptographic Seal Verification and Status Display
Given a share link embedding a signature over media hash, start/end timestamps, and halo configuration When the link is opened Then the signature is verified against ClipSpark's public key and the badge shows Verified if the signature and media hash match Given the signature does not validate or the media hash does not match the source asset When the link is opened Then the badge shows Unverified, playback remains available, and a prominent warning banner is displayed Given the verification service is temporarily unavailable When the link is opened Then the badge shows Unknown and the client retries verification up to 3 times with exponential backoff
Respect Access Controls, Watermarks, and Domain Restrictions
Given the source project enforces watermarking When the clip is played via share link or embed Then the watermark is visible on all frames during playback Given the project has a domain allowlist for embeds When the widget is embedded on a non-allowed domain Then the player refuses to render, displays "Domain not allowed", and returns an appropriate error event Given the source asset restricts public downloads When a public viewer accesses the share link Then no download controls are shown and direct media URLs require short-lived signed requests (<=5 minutes)
Embeddable Widget Preserves Verification Indicators Externally
Given the share link is embedded via the official widget on an external site When the widget loads Then the verification badge, halo visualization, and expand-only control are present and behave identically to the ClipSpark app Given the embed host origin is not on the allowlist When the page attempts to load the widget Then the widget blocks rendering using origin checks and appropriate security headers (e.g., CSP/X-Frame-Options) Given the viewer expands the halo in the embed When playback continues Then the expanded context plays and the sealed segment and badge remain unchanged
Audit Tracking of Views, Interactions, and Verification Outcomes
Given any share link is opened When the page loads Then an audit event is recorded with timestamp, link ID, referrer domain, anonymized IP/UA, geo country (if enabled), and verification result (Verified/Unverified/Unknown), without storing PII Given playback begins or the halo is expanded When the interaction occurs Then the audit log records the event type, duration played, expansion count and seconds added Given a link is expired or revoked When an access attempt occurs Then an audit event records the attempt with reason (Expired/Revoked) and the resulting HTTP status
Export With Halo Metadata
"As a social team member, I want exports to include halo metadata so that downstream tools and stakeholders can verify context."
Description

Extend export pipelines (MP4, WAV, SRT/VTT, JSON, EDL/FCPXML/Premiere) to include optional halo media and metadata. For media exports, include the halo as pre/post roll or as markers; for text exports, add halo timestamp ranges and verification hashes in sidecar files. Provide per-export toggles to include halo content, metadata, and verification signatures. Ensure downstream tools can reconstruct or validate the halo using provided markers and signatures.

Acceptance Criteria
Per-Export Halo Toggles Available and Persisted
Given a project with highlights that have a configured halo buffer of 20s and the export panel is opened for each supported format (MP4, WAV, SRT/VTT, JSON, EDL/FCPXML/Premiere) When the user inspects the options per format Then three independent toggles are visible: "Include Halo Content", "Include Halo Metadata", and "Include Verification Signatures" And each toggle has a tooltip describing its effect And the first time in a project all three toggles default to Off And after an export the last-used toggle states persist per project and per format. Given an export via public API When the request includes haloContent (bool), haloMetadata (bool), and haloSignatures (bool) Then the export behavior matches the UI for each combination And when a toggle is omitted it defaults to the last-used value for that project and format, or Off if none exists.
MP4/WAV: Pre/Post-Roll and Markers Behavior
Given a single highlight clip of duration D=60.0s and a halo buffer H=10.0s When exporting MP4 with Include Halo Content=On and Include Halo Metadata=Off Then the resulting media duration equals D + (2×H) within ±1 video frame tolerance And no container markers related to halo are present. Given the same clip When exporting MP4 with Include Halo Content=Off and Include Halo Metadata=On Then the media duration equals D within ±1 frame And the file contains four markers: halo_start (t=clip_in−H), core_start (t=clip_in), core_end (t=clip_out), halo_end (t=clip_out+H) And marker timestamps are accurate within ±1 frame And marker names follow pattern "Halo:{clip_id}:{tag}". Given the same clip When exporting WAV with Include Halo Content=On Then the resulting audio duration equals D + (2×H) within ±1 audio sample tolerance at the output sample rate And a Broadcast Wave (bext)/cue or equivalent marker list is added only if Include Halo Metadata=On. Given the same clip When exporting with both Include Halo Content=On and Include Halo Metadata=On Then both pre/post-roll and the four markers are present as specified.
Text Exports: Sidecar Halo Metadata and Signatures
Given an export to SRT and Include Halo Metadata=On When the export completes Then a sidecar file named {basename}.halo.json is created in the same directory And the original SRT contents are unchanged And the sidecar contains an array where each item has: clip_id (string), halo_start, core_start, core_end, halo_end (seconds with ≥3 decimal precision), hash.algorithm (e.g., "sha256"), hash.value (hex-encoded) And if Include Verification Signatures=On, each item also has signature.algorithm (e.g., "ed25519"), signature.value (base64), and public_key_fingerprint (string). Given exports to VTT and JSON transcript formats with Include Halo Metadata=On When the export completes Then a {basename}.halo.json sidecar is produced with the same schema And if Include Halo Metadata=Off then no halo sidecar is produced for any text export.
EDL/FCPXML/Premiere XML: Halo Representation and Importability
Given a highlight clip with halo buffer H=15s When exporting FCPXML with Include Halo Metadata=On Then the XML includes marker events for halo_start, core_start, core_end, halo_end with names "Halo:{clip_id}:{tag}" And when importing into Final Cut Pro 10.6+ those markers appear at the correct timeline positions within ±1 frame. Given the same clip When exporting Premiere XML with Include Halo Metadata=On Then sequence markers or clip markers encode the four halo boundaries And importing into Adobe Premiere Pro 24.0+ shows the markers within ±1 frame. Given the same clip When exporting EDL with Include Halo Metadata=On Then halo boundaries are represented via comments or auxiliary events per EDL capability And a provided mapping guide allows reconstruction of halo_start/core/halo_end within ±1 frame on import to supported NLEs. Given any of these timeline formats and Include Halo Content=On When importing to the target NLE Then the clip appears extended by H on both head and tail (bounded by available media) or as adjacent pre/post-roll segments labeled accordingly.
Cryptographic Hashes and Verification Signatures
Given any export with Include Halo Metadata=On and Include Verification Signatures=On When the export completes Then each halo entry (media or sidecar) includes a hash.algorithm of "sha256" and a hash.value matching the computed digest of the halo time range used for export And a detached signature (signature.algorithm="ed25519") over the hash.value is included along with public_key_fingerprint. Given the exported assets and the official verification tool When running verification against the files without modification Then verification returns Valid for all halo entries. Given the exported assets and any single-byte alteration within a halo time range When running verification Then verification returns Invalid for the altered entry and identifies the failing clip_id.
Downstream Reconstruction and Validation
Given an MP4 export with Include Halo Metadata=On (markers present) and Include Halo Content=Off When a supported downstream script/plugin ingests the MP4 in Adobe Premiere Pro 24.0+ Then it reconstructs halo pre/post boundaries as subclips whose in/out times match the original within ±1 frame. Given an SRT export with {basename}.halo.json sidecar containing signatures When a downstream validator processes the SRT + sidecar Then it reports that halo boundaries and signatures are valid and correspond to the transcript segments. Given an FCPXML export with Include Halo Content=On and Include Halo Metadata=On When imported into Final Cut Pro 10.6+ Then the resulting sequence contains extended clips (or adjacent pre/post-roll clips) and halo markers aligned within ±1 frame of the source halo definition.

Exhibit Forge

One-click builds a court-ready bundle: paginated PDF with quote, speaker, and timestamps; QR deep-link to the exact moment; authenticated audio snippet; hash manifest; Bates numbering; and a verifier sheet. Cuts paralegal assembly time and prevents filing rework.

Requirements

One-Click Exhibit Bundle Orchestrator
"As a litigation paralegal, I want to generate a complete court-ready exhibit bundle with one click so that I can file accurate materials quickly without manual assembly."
Description

A single action triggers an idempotent pipeline that assembles all required exhibit artifacts from a selected video moment or range, including the paginated PDF, QR deep-link, authenticated audio snippet, hash manifest, Bates numbering, and verifier sheet. The orchestrator runs as a background job with progress tracking, retry on transient failures, and eventual consistency guarantees. It integrates with ClipSpark’s timeline and highlights, respects user permissions and matter-level access controls, and stores outputs in secure, immutable object storage with versioning. The flow supports configurable templates, localized timezones, and naming conventions, and returns a downloadable bundle plus itemized links. Audit logs capture inputs, outputs, and operator identity for compliance.

Acceptance Criteria
Idempotent One-Click Orchestration from Selected Timeline Range
Given an authenticated user with access to a matter selects a time range [t1, t2] on the ClipSpark timeline or a saved highlight When they click "Build Exhibit Bundle" Then exactly one orchestration job is enqueued with the selected inputs and a unique job ID And if the same inputs (asset, [t1, t2], template, timezone, naming convention) are submitted again within 24 hours Then the generated artifacts have identical SHA-256 hashes to the prior run and the same job-level logical version And no additional Bates numbers are consumed or reserved And the selection boundaries used across all artifacts are within ±100 ms of [t1, t2] And a selection of a single timestamp produces the configured default snippet duration (e.g., 15s) centered within ±250 ms
Artifact Completeness and Court-Ready Formatting
Given the orchestration job completes successfully When the bundle is generated Then the bundle contains: (1) a paginated PDF with transcript quote text, speaker labels, and start/end timestamps printed on each relevant page; (2) a QR code embedding a deep link to the exact start timestamp; (3) an authenticated audio snippet covering the selected range; (4) a hash manifest listing each artifact filename, byte size, and SHA-256; (5) Bates numbering printed on every PDF page; (6) a verifier sheet summarizing inputs and checksums And the QR deep link opens the player at the selection start within ±250 ms And the PDF page numbers increment sequentially and match the table of contents (if present) And the audio snippet file integrity validates against the manifest hash and plays for the expected duration within ±100 ms And Bates numbers are unique across the bundle and follow the configured prefix and zero-padding
Configurable Templates, Localized Timezones, and Naming Conventions Applied
Given a user selects template T, timezone Z, and naming convention N for a matter When the orchestration job runs Then the PDF layout and styling match template T (header/footer, logo, typography, and fields rendered as defined) And all human-readable timestamps in artifacts render in timezone Z, including PDF, verifier sheet, and deep-link display parameters And all generated filenames conform to naming convention N (including tokens for matter ID, asset ID, t1-t2, and version), with no illegal characters for the target filesystem And changing T, Z, or N and re-running with identical inputs produces different outputs only where those settings apply (e.g., filenames, layout, timestamp display) while content hashes for unchanged assets remain stable
Background Job Progress, Retries, and Eventual Consistency
Given an orchestration job is enqueued When the user views job status Then the job exposes states: queued, running, retrying, completed, failed, with percent complete updating at least every 5 seconds while running And transient errors (e.g., HTTP 5xx, timeouts, object-store throttling) trigger up to 3 automatic retries with exponential backoff And retries do not create duplicate artifacts or consume additional Bates numbers And on completion, all itemized links and the bundled download become available only after a successful retrieval check passes for each artifact And eventual consistency is achieved such that all links are resolvable within 30 seconds of completion, or the job remains in a reconciling state until resolvable And on failure after max retries, the job surfaces last error code(s) and correlation ID(s) in the status payload
Permissions and Matter-Level Access Controls
Given a user without access to the matter attempts to initiate a bundle When they click "Build Exhibit Bundle" Then the request is rejected with HTTP 403 and no job is created Given a user with access to the matter initiates a bundle for an asset within that matter When the job is created Then the job runs and artifacts are only accessible to users with equivalent or higher permissions on that matter And cross-matter references (assets, templates, or storage paths) are blocked and logged And status endpoints and download links enforce the same authorization checks And any denied access attempts are captured in the audit log without leaking sensitive content
Immutable Versioned Storage and Download Delivery
Given artifact generation completes When artifacts are written to object storage Then server-side encryption is enabled (AES-256 or KMS-managed) and bucket versioning is on And objects are immutable (no overwrite-in-place); updates create new versions and prior versions remain readable to authorized roles only And the API returns a downloadable ZIP bundle plus itemized pre-signed URLs for each artifact And pre-signed URLs expire within 24 hours and are regenerated on request by authorized users And the ZIP bundle’s SHA-256 matches the value recorded in the manifest And direct object HEAD requests for each URL succeed with ETag/Content-Length matching the manifest
Comprehensive Audit Logging and Compliance Traceability
Given any orchestration job is created, updated, or completed When audit records are inspected Then each record includes: operator user ID and role, matter ID, job ID, video asset ID, input selection [t1, t2], template ID, timezone, naming convention ID, request timestamp, status transitions with timestamps, retry count with error codes, output artifact identifiers (paths, versions) with SHA-256 hashes And audit records are append-only and tamper-evident; attempts to alter produce a new audit event and do not modify prior entries And audit records are queryable by job ID, matter ID, and date range, returning results within 2 seconds for up to 10,000 records And downloading audit exports reproduces the recorded hashes for all artifacts listed
Court-Ready PDF Composer
"As an attorney, I want a properly formatted, paginated PDF that cites speaker and timestamps so that the document is acceptable to the court and easy to reference."
Description

Generates a PDF/A-2b compliant, paginated document containing the quoted transcript excerpt, speaker attribution, and start/end timestamps with precise timecode formatting. Applies court-appropriate typography, margins, and line spacing; inserts Bates numbers in header or footer; embeds the QR code and human-readable deep-link; and ensures consistent styles across multi-page excerpts. Handles quotes that span multiple pages, includes optional contextual lines before/after the excerpt, and supports redaction blocks and highlighting. Produces selectable text (not rasterized), bookmarks, and embedded metadata (matter ID, date, generator version) to meet e-filing requirements and facilitate searchability.

Acceptance Criteria
PDF/A-2b Compliance and Selectable Text
Given a prepared transcript excerpt and a selected court style When the PDF is generated Then the output validates as PDF/A-2b with zero errors using a standards-compliant validator And then all fonts are embedded and subset and an ICC color profile is embedded And then the document text is selectable and copyable with at least 99% of visible characters extractable And then no page is rasterized or composed entirely of images And then the XMP metadata includes pdfaid:part=2 and pdfaid:conformance=B
Speaker Attribution and Timecode Formatting
Given a multi-speaker transcript excerpt with defined start and end times When composing the excerpt section Then each utterance is prefixed with the exact provided speaker label And then the excerpt header displays Start and End timecodes in hh:mm:ss.mmm format with zero-padding And then any displayed timecodes match the regex ^\d{2}:\d{2}:\d{2}\.\d{3}$ And then speaker changes begin on new lines and are preserved across page breaks
Court Typography, Margins, and Line Spacing
Given the selected Court Standard style (font family, font size, margins, line spacing, page number style) When the document is rendered Then page margins equal the configured values within ±0.5pt And then line spacing equals the configured multiple across all paragraphs And then the configured font family and size are applied to body, headers, and footers consistently And then running page numbers render in the configured location and do not overlap body content And then widow/orphan control prevents single lines at the top or bottom of a page
Bates Numbering Placement and Sequencing
Given Bates numbering settings (prefix, start number, zero-pad length, location, alignment) When generating the PDF Then every page displays a Bates number matching the configured pattern prefix + zero-padded sequential number And then the sequence increments by 1 per page starting from the configured number And then placement appears in the selected header or footer area and stays within margins without overlapping body text And then the first and last Bates numbers are recorded in document metadata
QR Code and Deep-Link Embedding
Given a deep-link URL targeting the exact media timestamp When composing the first page of the excerpt Then a QR code is embedded that decodes exactly to the deep-link URL And then a human-readable clickable hyperlink with the same target is present And then both the QR code and hyperlink resolve successfully (HTTP 2xx) during validation And then no prohibited interactive content is present and PDF/A-2b compliance is maintained
Multi-Page Flow, Context Lines, and Continuations
Given an excerpt that spans multiple pages and a context setting of N lines before and after When generating the document Then exactly N preceding and N following context lines are included and visually distinguished per style settings And then page breaks do not split words; if a line must break, hyphenation is applied per style rules And then continuation markers (e.g., “(continued)”) appear at the bottom of the broken page and top of the next page And then speaker labels, indentation, and numbering persist correctly across pages
Redaction and Highlighting Fidelity
Given specified redaction ranges and highlight ranges within the excerpt When producing the PDF Then redacted text is removed from the content stream and replaced with vector blackout rectangles And then copying or text extraction does not reveal any redacted content And then highlight overlays render with the configured color and 30–60% opacity over selectable text And then printing preserves both redactions and highlights without artifacts And then the file remains PDF/A-2b compliant
Bookmarks and Embedded Metadata for E-Filing
Given matter ID, exhibit label, filing date, and generator version When composing the document Then XMP metadata includes dc:title, pdf:Producer (generator version), custom:matterId, custom:exhibitLabel, and xmp:CreateDate in ISO 8601 And then the document info dictionary mirrors key fields where allowed And then bookmarks are created with a top-level entry for the exhibit label and a child entry named with the excerpt’s start–end timestamps linking to the first excerpt page And then metadata and bookmarks persist when reopened in standard PDF readers
QR Deep-Link Generator
"As a filing coordinator, I want scannable codes that jump to the exact moment in the recording so that reviewers can instantly verify context without scrubbing."
Description

Creates print-safe QR codes (300+ DPI, error correction level H) that resolve to signed, permission-checked URLs pointing to the exact media timestamp in ClipSpark’s web player. Links include immutable references to the media version and timecode while allowing forward-compatible redirects if sources are re-hosted. The generator inserts QR codes into the PDF and verifier sheet, provides alt text and a short human-readable URL, and optionally tracks scan events for audit. Signed links have configurable TTLs and can be invalidated on revocation while preserving an offline fallback that encodes exhibit ID, Bates range, and timecode for manual lookup.

Acceptance Criteria
Print-Safe QR Code Generation
- Given a request to generate a QR code, When the output is produced, Then the raster export is at least 300 DPI and the vector export is SVG with no embedded bitmaps. - Given QR generation, When encoding occurs, Then error correction level is H and the quiet zone is at least 4 modules on all sides. - Given CMYK print workflows, When the QR is placed in the PDF, Then modules are pure black (C0 M0 Y0 K100) on a white background with >= 7:1 contrast ratio. - Given a printed size of 20 mm x 20 mm, When scanned by current iOS and Android native camera apps, Then decode success is >= 99% across 10 separate test prints. - Given the layout engine scales assets, When the QR would render below 15 mm, Then the generator blocks insertion and surfaces a warning unless an admin override flag is set.
Signed Deep-Link Permissions and TTL
- Given an authenticated user with exhibit view permission, When they scan the QR, Then the URL resolves via 302 to the ClipSpark player and returns HTTP 200. - Given a user without permission, When they scan the QR, Then the service returns HTTP 403 with a redacted message and support contact link; no media URL is leaked. - Given a TTL of N hours configured, When the QR is scanned after TTL expiry, Then the service returns HTTP 410 "Link expired" and displays verifier sheet lookup instructions. - Given exhibit or user access is revoked, When the QR is scanned, Then the link becomes invalid within 60 seconds and returns HTTP 410 with a revocation reason code. - Given any tampering with path/query parameters, When the URL is requested, Then signature validation fails and the service returns HTTP 401 with no redirect. - Given a generated signed link, When inspecting the token, Then it contains immutable media_version_id and timecode parameters and uses a non-guessable token (>= 128 bits entropy).
Exact Timestamp Resolution in Web Player
- Given a signed deep-link with timecode T, When opened in the ClipSpark web player, Then playback begins at T with <= 0.5 s tolerance. - Given seek constraints (trimmed bounds), When the link opens, Then playback starts at the nearest allowed frame to T and the displayed timestamp reflects the effective start. - Given speaker metadata at T, When the player loads, Then the speaker name and quote snippet render within 1 second of player ready. - Given the user changes playback rate, When playback begins from the deep-link, Then the starting offset remains consistent relative to T. - Given adaptive streaming (HLS/DASH) under variable network, When opening via deep-link, Then initial seek accuracy remains within <= 0.5 s.
QR Insertion into PDF and Verifier Sheet
- Given a generated QR for a quoted segment, When Exhibit Forge compiles the paginated PDF, Then the QR is placed adjacent to the corresponding quote block and appears on the verifier sheet per template without overlapping other content. - Given accessibility requirements, When exporting the PDF, Then each QR has alt text "Scan to open ClipSpark at HH:MM:SS for Exhibit {ID}" and a short human-readable URL printed below of <= 30 characters. - Given Bates numbering for the exhibit, When QR captions are rendered, Then the Bates range matching the quote's page span is included and correct. - Given PDF/A-2b validation, When the PDF is checked, Then QR embeddings do not break compliance. - Given pagination changes during reflow, When the document is rebuilt, Then each QR repositions to remain adjacent to its source quote and on the correct page.
Forward-Compatible Redirects on Re-Hosting
- Given media is re-hosted or migrated, When the signed link is accessed, Then a redirect mapping preserves access without altering media_version_id and timecode semantics. - Given no redirect mapping exists, When the signed link is accessed, Then the service returns HTTP 502 with a Retry-After header and raises an admin alert. - Given an active mapping and valid permissions, When the link is accessed, Then end-to-end resolution completes in <= 600 ms at P95. - Given redirect mappings are updated, When prior links are used, Then caches do not serve stale targets for more than 5 minutes (cache-busting honored).
Optional Scan Event Tracking for Audit
- Given tracking is disabled by default, When a QR is scanned, Then no audit event is persisted beyond transient operational logs. - Given tracking is enabled at the exhibit level, When a QR is scanned, Then an audit record captures timestamp, exhibit_id, bates_range, timecode, link_status (success/expired/forbidden), country-level geolocation, and user_agent; IP is stored only as salted hash per policy. - Given a user requests an audit export, When generated, Then a CSV is available within 1 minute containing the captured fields and excluding raw PII. - Given sustained load of 100 scans per second, When tracking is enabled, Then event capture incurs < 200 ms latency overhead at P95 with < 1% event loss. - Given a data retention policy of N days, When events exceed retention, Then they are purged automatically and the purge is reflected in event counts within 24 hours.
Offline Fallback and Manual Lookup
- Given no network connectivity, When the QR is decoded offline, Then the payload contains exhibit_id, bates_range, and timecode using the schema ex:{id}:{bates_start}-{bates_end}@{HH:MM:SS.ff}. - Given an expired or revoked link, When the landing page is displayed, Then the offline fallback string is shown prominently with a copy button and manual lookup instructions. - Given the verifier sheet and fallback values, When a clerk performs a manual lookup, Then the corresponding media and timestamp are located within 3 steps. - Given physical QR degradation, When scanned, Then error correction level H enables successful decode with up to 30% module damage in at least 9/10 test cases.
Authenticated Audio Snippet Export
"As a records specialist, I want a tamper-evident audio clip of the quoted segment so that the authenticity of the spoken words can be independently verified."
Description

Extracts a precise audio segment for the cited time window with frame-accurate start/stop, normalizes loudness (e.g., -16 LUFS), and exports in court-accepted formats (WAV and MP3). Each file embeds provenance metadata (source media ID, timecode range, transcript hash) and a cryptographic signature to prove authenticity. Optional features include profanity beeps or redaction muting, sample-rate conversion, and spectral watermarking. Outputs are stored immutably, referenced in the manifest, and linked from the PDF and verifier sheet for quick access and independent verification.

Acceptance Criteria
Frame-Accurate Snippet Extraction
Given a source media with known frame rate and timecodes When the user exports an audio snippet for a specified start and end timecode Then the exported audio starts at the requested start within ≤1 sample at the target sample rate And the exported audio ends at the requested end within ≤1 sample at the target sample rate And the exported duration equals (end − start) within ±1 sample And no leading or trailing padding is added and no content within the window is omitted And waveform alignment against the source shows no cumulative drift across the segment
Loudness Normalization to −16 LUFS
Given loudness normalization is enabled When exporting any snippet Then integrated loudness measured per ITU-R BS.1770-4 equals −16.0 LUFS ± 0.5 LU And true-peak level does not exceed −1.0 dBTP And inter-channel phase and relative gain are preserved And the applied normalization settings are recorded in the manifest and file metadata
Court-Accepted Exports: WAV and MP3
Given default export settings When the user exports a snippet Then two files are produced: WAV (BWF PCM s16le) and MP3 (MPEG-1 Layer III) And media probes identify WAV codec pcm_s16le with a BWF bext chunk and MP3 codec mp3 And the durations of both files match the requested window within ≤1 ms And the output sample rate equals the selected target (e.g., 44.1 kHz or 48 kHz) And filenames include source media ID and timecode range
Provenance Metadata and Cryptographic Signature Embedded
Given the export completes When reading the embedded metadata of each file Then WAV contains BWF/iXML fields for SourceMediaID, TimecodeStart, TimecodeEnd, and TranscriptHash with values matching the manifest And MP3 contains ID3v2 TXXX frames for SourceMediaID, TimecodeStart, TimecodeEnd, and TranscriptHash with values matching the manifest And each file contains an embedded signature field and an accompanying detached .sig created using Ed25519 over the file bytes (excluding the signature field for the embedded variant) And verification with the public key on the verifier sheet returns VALID for unmodified files And modifying any byte in a file causes signature verification to FAIL
Spectral Watermarking (Optional)
Given spectral watermarking is enabled When exporting a snippet Then a watermark detector reports Present with confidence ≥ 0.95 on the exported WAV and MP3 And detection still succeeds (confidence ≥ 0.90) after re-encoding the MP3 at 192 kbps and resampling to 44.1 kHz And integrated loudness change versus the unwatermarked export is ≤ 0.1 LU and true-peak change is ≤ 0.2 dB And when watermarking is disabled, the detector reports Absent (false positive rate ≤ 0.05)
Profanity Beep and Redaction Muting
Given flagged word or phrase time ranges are available from the transcript or manual selection When exporting with Beep enabled Then audio within flagged ranges is replaced by a 1 kHz tone at program loudness with 5 ms fades at boundaries and no bleed outside the ranges And when exporting with Mute enabled, audio within flagged ranges is rendered ≤ −90 dBFS with 5 ms fades at boundaries And all redaction events and time ranges are recorded in the manifest and embedded metadata And audio outside flagged ranges is unchanged relative to the non-redacted export
Immutable Storage, Manifest Reference, and PDF/Verifier Links
Given content-addressed immutable storage is configured When the export completes Then each output file is written once with a SHA-256 digest and content address that reproduces identical bytes on subsequent reads And the manifest lists for each file: filename, byte size, MIME type, timecode range, SHA-256, integrated loudness, options applied, and signature algorithm And the Exhibit PDF and verifier sheet include a URL and QR that resolve in ≤ 2 seconds via HTTPS to the exact file (HTTP 200) And downloading via the link yields a file whose SHA-256 matches the manifest And any attempt to modify or overwrite a stored object is rejected by the storage layer
Cryptographic Hash Manifest
"As a compliance officer, I want a signed manifest of all artifact hashes so that I can prove no files were altered after generation."
Description

Computes SHA-256 (and optional SHA-512) hashes for every artifact in the bundle, producing a manifest.json and a human-readable summary that list filenames, sizes, algorithms, and checksums alongside creation timestamps and generator versions. The manifest itself is signed using a service key to prevent substitution and includes a verification guide. A lightweight verifier CLI/script is provided to re-hash files and validate signatures offline. The manifest is embedded in the bundle and referenced by the verifier sheet, enabling end-to-end integrity checks and chain-of-custody evidence.

Acceptance Criteria
Manifest Generation with SHA-256 and Optional SHA-512
Given an Exhibit Forge bundle build is initiated with default settings When manifest generation completes Then manifest.json exists at path "ExhibitForge/manifest.json" And manifest.json contains one entry per artifact file included in the bundle, excluding "ExhibitForge/manifest.json" and "ExhibitForge/manifest.json.sig" And each entry includes: filename (relative path), sizeBytes (integer), createdAt (UTC ISO-8601 with 'Z'), generator.version (semantic version), algorithms array including "SHA-256", checksums object keyed by algorithm name with lowercase hex digest And each SHA-256 value is exactly 64 lowercase hex characters Given the "includeSha512" option is enabled When generation completes Then each entry additionally includes a SHA-512 value of exactly 128 lowercase hex characters; otherwise no SHA-512 is present And manifest.json validates against the published JSON schema file "schemas/manifest.v1.json"
Manifest Signature Creation and Offline Verification
Given a service private key is configured on the build node When manifest.json is finalized Then a detached signature file "ExhibitForge/manifest.json.sig" is produced referencing the manifest and including a keyId And the verifier CLI invoked as "verifier verify --manifest ExhibitForge/manifest.json --signature ExhibitForge/manifest.json.sig --pubkey service.pub" with no network access returns exit code 0 and prints "SIGNATURE: VALID" When any byte of manifest.json is modified Then the same command returns exit code 3 and prints "SIGNATURE: INVALID"
Verifier CLI Re-Hash Validation of Bundle Artifacts
Given a bundle directory, a validated manifest.json, and its valid signature When the verifier CLI is invoked as "verifier check --bundle . --manifest ExhibitForge/manifest.json" Then it re-computes SHA-256 for each file listed and compares to the manifest And for each file it prints one of: "OK <relativePath>", "MISMATCH <relativePath>", or "MISSING <relativePath>" And if any mismatch or missing is detected, the process exits with code 2; if all files are OK, it exits with code 0 Given "--alg sha512" is provided and SHA-512 values exist in the manifest When verification runs Then SHA-512 is used for comparisons; otherwise SHA-256 is used
Manifest Embedded and Cross-Referenced by Verifier Sheet
Given a completed bundle When the verifier sheet PDF is opened Then it contains a section titled "Integrity Verification" that lists the embedded manifest path "ExhibitForge/manifest.json" and signature path "ExhibitForge/manifest.json.sig" And the verifier sheet includes step-by-step offline instructions for running the verifier CLI with example commands referencing the embedded paths And the verifier sheet displays the service keyId used to sign the manifest
Human-Readable Manifest Summary Completeness and Accuracy
When the bundle is generated Then a human-readable summary file "ExhibitForge/manifest-summary.txt" exists And it lists, for every manifest entry, the filename, sizeBytes, createdAt, and SHA-256 (and SHA-512 if present) in a tabular or line-oriented format And entries are sorted lexicographically by relative filename And a footer shows "Total files: <N>" that matches the count of entries in manifest.json And randomly sampling 5 entries, the values in the summary exactly match the corresponding values in manifest.json
Pinned Service Public Key Prevents Manifest Substitution
Given the verifier CLI bundles the ClipSpark service public key set and recognizes keyIds When verifying a manifest signed with a known keyId Then signature validation succeeds offline (exit code 0) When a manifest is replaced by another manifest signed with an unknown keyId or different service key Then validation fails offline with exit code 3 and message "UNKNOWN SIGNING KEY" And the verifier sheet displays the expected keyId, which matches the keyId embedded in the valid signature
Clear Errors and Exit Codes for Verification Failures
Rule: The verifier CLI uses standardized exit codes: 0=OK, 2=HASH_ERRORS (mismatch/missing/extra), 3=SIGNATURE_INVALID, 4=MANIFEST_PARSE_ERROR, 5=IO_ERROR Given a truncated manifest.json When "verifier verify" runs Then it exits with code 4 and prints a JSON parse error message containing the filename Given an extra file exists in the bundle that is not listed in manifest.json and "--fail-on-extra" is provided When "verifier check" runs Then it prints "EXTRA <relativePath>" and exits with code 2
Bates Numbering Engine
"As a paralegal, I want consistent, collision-free Bates numbers applied across the exhibit so that pagination and references align across filings and teams."
Description

Applies sequential Bates numbers across all PDF pages and attachments in the bundle with support for configurable prefixes, zero-padding, and matter-specific counters. Ensures collision-free assignment across multiple bundles by reserving ranges, supports resuming sequences, and records allocations in an auditable registry. Placement (header/footer, left/center/right) and typography are configurable per template while preserving PDF/A compliance. The engine exposes a preview mode and validates that the Bates range matches the verifier sheet and manifest entries before finalization.

Acceptance Criteria
Sequential Bates numbering across bundle and attachments with prefix and zero-padding
Given a bundle of 3 PDFs totaling 125 pages and a template with prefix "MAT-23-", zero-padding 7, and starting counter 456 When the Bates Numbering Engine applies numbers to the entire bundle Then page 1 is stamped "MAT-23-0000456" and the final page is "MAT-23-0000580" And numbering increments by 1 per page without resetting between attachments And each page receives exactly one Bates stamp And the assigned numbers match the reserved range length exactly
Collision-free range reservation across concurrent bundles
Given an allocated range MAT-23-0000100 to MAT-23-0000199 exists in the registry And two users concurrently request overlapping ranges When reservations are processed Then only one reservation succeeds and the other receives a 409 conflict with the conflicting range detailed And the registry contains no overlapping reserved or allocated ranges And the reserved range size equals the page count to be stamped for the requesting bundle
Resume numbering after interruption without gaps or duplication
Given stamping succeeded through "MAT-23-0000507" and then failed due to an I/O error When the job is resumed with the same bundle ID and template Then stamping continues at "MAT-23-0000508" with no duplicated or skipped numbers And previously stamped pages are not altered And the registry reflects the exact consumed range after completion
Configurable placement and typography while preserving PDF/A compliance
Given a template specifying footer-right placement, font "Noto Sans", size 9pt, 80% black, and a 10pt margin And the bundle contains mixed page sizes and rotations (A4 portrait, Letter landscape, 90° rotated) When Bates stamps are applied Then each stamp appears in the footer-right within the defined margin respecting page rotation and size And stamps do not obscure more than 2% of existing text bounding boxes per page And the output validates as PDF/A-2b via automated verification (e.g., veraPDF)
Accurate preview mode showing positions and calculated range prior to finalization
Given preview mode is invoked for pages 1, 10, and the last page with the selected template When the preview is rendered Then overlays display the exact Bates strings and positions that will appear in the finalized PDF And the preview shows the expected first and last Bates numbers based on total page count And a warning is shown if a stamp would exceed the margin or cross the overlap threshold
Range and manifest verification before finalization
Given a verifier sheet lists first and last Bates numbers and the manifest contains per-page hashes When finalization is requested Then the engine compares the computed first/last numbers and per-page hashes against the verifier sheet and manifest And blocks finalization with a descriptive error at the first mismatch And on success it records a validation confirmation linked to the bundle in the registry
Auditable registry entry for allocations and completions
Given stamping completes for bundle ID "B123" When the registry is queried Then an immutable entry exists including bundle ID, user, timestamp, template ID, reserved range, consumed range, first/last numbers, and verifier sheet checksum And the entry is exportable as JSON and CSV And attempts to modify an existing entry are rejected with 403 and an audit log is appended
Verifier Sheet and Chain-of-Custody
"As a court clerk, I want a concise verifier sheet with hashes and provenance so that I can quickly assess authenticity and locate supporting artifacts."
Description

Generates a front-matter sheet summarizing the exhibit: matter details, media source, quoted range, Bates range, QR preview, artifact list, and cryptographic hashes with signature status. Includes generation timestamp, operator identity, environment, and software version, plus optional digital signature or notarization. Provides concise instructions and QR/URL for verification and links to the downloadable audio snippet. Appends an event ledger capturing key actions (selection, generation, download, revocation) to establish chain-of-custody. Designed for clear print readability and PDF/A conformance.

Acceptance Criteria
Front-Matter Metadata Completeness
Given a user generates an Exhibit Forge bundle for a specified matter When the verifier sheet is produced Then the front-matter displays the following non-empty fields: Matter Name, Matter ID, Jurisdiction (if provided), Media Source (filename and storage URI), Quoted Transcript Range (start timestamp to end timestamp), Bates Range (start to end), Artifact List (names and types), Generation Timestamp (UTC ISO 8601), Operator Identity (name or ID), Execution Environment (workspace/tenant), and Software Version (semantic version) And any unavailable optional field is rendered as 'N/A' and not left blank And a QR preview for verification is present with image size ≥ 180x180 px encoding the verification URL
Hash Manifest and Signature Status Correctness
Given the verifier sheet includes a hash manifest of all generated artifacts (PDF, audio snippet, transcript excerpt, manifest) When SHA-256 is recomputed over each artifact and compared Then each manifest digest exactly matches the recomputed value And each artifact row includes a Signature Status with one of: Valid, Invalid, Not Signed And for Signed artifacts, verifying the embedded signature returns Valid and displays signer CN and signing time; for Invalid, verification returns Invalid with a reason; for Not Signed, no signature metadata is shown And if any artifact bytes are altered post-generation, the corresponding verification result reports Hash Mismatch
Verification QR/URL and Audio Snippet Accessibility
Given the verifier sheet presents a verification URL and QR code When the QR is scanned or the URL is opened by an authenticated user Then the verification page loads over HTTPS with HTTP 200 in ≤ 2 seconds (p95) and shows exhibit ID and hash summary And the deep link opens the source media at the quoted start time within ±500 ms and displays the quoted range And a link to download the authenticated audio snippet is present and returns Content-Type 'audio/mpeg' with duration equal to the quoted range ±1 second And unauthenticated requests to the audio snippet return HTTP 401 And the sheet includes a How to Verify section with ≤ 3 steps and ≤ 300 characters total
Chain-of-Custody Event Ledger Completeness
Given an exhibit is created, downloaded, and optionally revoked When the verifier sheet's event ledger is reviewed Then it contains entries for Selection, Generation, Download, and Revocation (if applicable) And each entry records UTC ISO 8601 timestamp, Actor (user ID or service), Action Type, Target Artifact (name or digest), and Outcome (Success/Fail) And entries are strictly chronological with non-decreasing timestamps And the ledger entries exactly match the system audit log for the exhibit ID
Bates Range and Quoted Range Consistency
Given the exhibit bundle includes a paginated PDF with Bates numbering When the verifier sheet displays the Bates range and quoted transcript timestamps Then the Bates range start and end match the first and last Bates numbers present in the generated PDF And the quoted start timestamp is ≤ end timestamp and both fall within the source media duration And the transcript excerpt for the quoted range matches source transcript content for those timestamps (ignoring whitespace normalization) And the QR deep link start time matches the quoted start within ±500 ms
PDF/A Conformance and Print Readability
Given the verifier sheet PDF is generated When validated against PDF/A-2b using veraPDF Then the file passes with zero errors And all fonts are embedded; body text is ≥ 10 pt, headings ≥ 12 pt, and text contrast ratio ≥ 4.5:1 And the on-page QR code is ≥ 0.8 inches per side and decodes successfully in ≥ 95% of scans when printed at 300 DPI on Letter and A4 And no content is clipped or overlaps when opened in Adobe Acrobat and native OS PDF viewers
Digital Signature or Notarization Option
Given organization policy requires signing or notarization When Digital Signature is enabled at generation Then the final PDF is signed with an X.509 certificate and validates as 'Signed and all signatures are valid' in Adobe Acrobat And the visible signature block displays signer name, organization, and RFC 3161 timestamp authority time And when Notarization is enabled, a notarization receipt or seal reference is embedded or linked and the verification page shows Notarized with provider name and receipt ID And when neither option is enabled, the verifier sheet states 'Not Digitally Signed' and includes no signature placeholder

Open Verifier

Offer a public, read-only verification portal and offline verifier so third parties can confirm quotes without a login. Paste a link or drag the source file to see pass/fail checks, chain details, and mismatch alerts—building trust beyond your workspace.

Requirements

Public Read-only Verification Portal
"As a third-party reviewer, I want to access a public verification page without logging in so that I can quickly validate quoted material from a recording."
Description

A web-based, publicly accessible, read-only portal that allows anyone to verify quotes and artifacts without authentication. The portal renders deterministic verification results derived from ClipSpark’s stored artifacts and processing logs, ensuring no modification of source data. It provides a clear summary of verification status, confidence, and timestamps, and supports desktop and mobile browsers with WCAG-compliant accessibility. The portal integrates with existing artifact storage, transcript services, and highlight metadata, and applies rate limiting and anonymized analytics to protect performance and privacy. Expected outcome is frictionless third-party validation that increases trust and shareability of ClipSpark outputs.

Acceptance Criteria
Public Access Without Authentication (Read-only)
Given a public verification link or artifact ID, When a user opens the portal, Then verification results render without requiring authentication. Given an unauthenticated user, When interacting with the portal, Then no write operations (POST/PUT/PATCH/DELETE) are executed and no state is persisted server-side. Given the browser network panel is inspected, When the session is active, Then only GET requests to read-only endpoints are made and succeed with 2xx responses.
Deterministic Verification Output and Summary
Given identical artifact inputs, When verification is executed multiple times on the same build, Then the portal displays identical verification status, confidence score, timestamps, and chain details. Given an artifact, When results are displayed, Then the summary includes overall status (Pass/Fail/Incomplete), confidence (0–100%), timestamps in hh:mm:ss.mmm format, chain details (source hash, transcript version, model/version), and mismatch alerts with their locations. Given the same artifact is verified across different browsers/devices, When the output JSON payload is compared, Then the SHA-256 hash of the results payload matches across runs.
Link and File Input Verification
Given a supported source URL, When the user clicks Verify, Then the URL is validated and verification begins within 2 seconds with visible progress. Given a user drags a supported file (mp4, mp3, wav, m4a, mkv, srt, vtt) up to 2 GB, When dropped on the portal, Then upload/ingest starts with progress feedback and verification executes to completion or a clear error. Given an unsupported format or size limit exceeded, When verification is initiated, Then the portal blocks the action and displays an actionable error with supported formats and limits. Given a successful file or URL verification, When results are shown, Then the portal confirms read-only processing (no source alteration) and displays derived hashes but never modifies the source content. Given keyboard-only users, When initiating file selection, Then an accessible “Choose file” control provides equivalent functionality to drag-and-drop.
WCAG 2.1 AA Accessibility Compliance
Given keyboard-only navigation, When traversing the portal, Then all interactive elements are reachable in a logical order with visible focus and no traps. Given a screen reader (NVDA/JAWS/VoiceOver), When reading the page, Then all controls and results have programmatically associated names/roles/states and tables are announced with headers. Given standard contrast testing, When measuring text and UI controls, Then contrast ratios meet or exceed 4.5:1 for text and 3:1 for large text/icons. Given status changes or errors, When updates occur, Then messages are announced via aria-live regions and are dismissible. Given reduced motion preferences, When animations would play, Then motion is minimized or disabled respecting prefers-reduced-motion.
Responsive Browser Support and Performance
Given common desktop browsers (Chrome, Safari, Firefox, Edge latest + previous), When loading the portal, Then all core flows work without visual/functional regressions. Given common mobile browsers (iOS Safari 15+, Android Chrome 11+), When loading the portal, Then the layout is responsive from 320px to 1920px with no horizontal scrolling and tap targets ≥44px. Given a 4G network (≈1.6 Mbps), When loading the verification results page cold, Then Time to Interactive is <3s and Largest Contentful Paint is <2.5s for median artifacts. Given an accessibility/performance audit, When running Lighthouse, Then scores are ≥90 for Accessibility and ≥80 for Performance on a representative page.
Rate Limiting and Privacy-Preserving Analytics
Given a single client exceeds 60 verification requests within 60 seconds, When further requests arrive, Then the portal responds 429 Too Many Requests with a Retry-After header. Given analytics events are emitted, When data is sent, Then no PII (names, emails, exact IPs) or full source URLs are logged; IPs are salted/hashed and truncated. Given the browser Do Not Track setting is enabled, When the portal loads, Then analytics collection is disabled for that session. Given cookie/storage inspection, When the portal runs, Then no third-party tracking cookies are set and only essential, non-identifying storage is used for session/CSRF protection if applicable.
Integration with Artifact Storage, Transcripts, and Highlights
Given a valid artifact ID or share link, When verification runs, Then the portal retrieves source artifacts, transcripts, and highlight metadata using read-only credentials and signed URLs without exposing internal storage paths. Given a dependency outage (e.g., transcript service), When verification executes, Then the portal surfaces a partial results state with clear warnings and sets overall status to Incomplete. Given the artifact has changed since link generation, When verification loads, Then the portal displays a version mismatch alert and allows viewing both referenced and current versions. Given chain details are shown, When the user expands them, Then source file hash, transcript checksum/version, model/version, and processing log references are displayed and copyable. Given timestamps in results, When a user clicks a timestamp, Then the embedded player (when available) seeks to that time within ±500ms.
URL and File Intake (Paste Link or Drag-and-Drop)
"As a verifier, I want to paste a link or drop a source file so that I can initiate verification without needing a ClipSpark account or specialized tools."
Description

A unified intake layer that accepts ClipSpark share links, public media URLs (e.g., YouTube, Vimeo), and direct file uploads via drag-and-drop for audio/video and caption formats (MP4, MP3, MOV, WAV, SRT, VTT). The intake normalizes sources, extracts basic metadata (duration, codecs, language), performs virus/malware scanning on uploads, computes preliminary hashes, and routes jobs to a verification worker queue. It displays upload and processing progress, enforces size/type limits, and provides clear error messages. This layer integrates with the portal UI and backend verification services to initiate verification without a ClipSpark account.

Acceptance Criteria
Paste ClipSpark Share Link
Given I am on the Open Verifier without logging in When I paste a valid ClipSpark share link and press Verify Then the intake validates the URL pattern, resolves the public asset, and displays normalized source title and duration within 3 seconds And a verification job is created once with a visible Job ID Given I paste an invalid or expired ClipSpark share link When I press Verify Then I see an inline error "Invalid or expired ClipSpark link" with a support code and no job is created Given I paste a valid ClipSpark share link When the backend cannot reach the resource due to network or permissions Then I see an error stating the specific cause (e.g., 403 Forbidden, 404 Not Found, Timeout) and a retry option
Paste Public Media URL (YouTube/Vimeo/Direct)
Given I paste a publicly accessible YouTube, Vimeo, or direct media URL When I press Verify Then the intake normalizes the URL (resolves redirects) and validates public accessibility And basic metadata (duration, container, codecs, resolution if video, audio bitrate) is displayed And a verification job is queued with a Job ID Given I paste a private/unlisted URL requiring auth or a geo-restricted URL When I press Verify Then I receive a clear error explaining access restrictions and that no job was created Given the URL exceeds configured maximum media duration or size (as reported via headers or probe) When I press Verify Then I am shown a limit error including the configured maximum values and guidance to trim or upload a file instead
Drag-and-Drop Media and Caption Files
Given I drag-and-drop a supported media file (MP4, MP3, MOV, WAV) optionally with a single caption file (SRT or VTT) When the files enter the drop zone Then the drop zone is highlighted and lists the files with their types and sizes Given I drop the files When upload starts Then per-file upload progress (0–100%) is shown and a combined overall progress bar is displayed Given I drop unsupported file types or more than one media file When validation runs Then I see an error specifying unsupported types and allowed types, or that only one media file is allowed, and upload is blocked Given I am using the offline verifier When I drag-and-drop supported files Then the intake proceeds without any login prompts and disables URL input, allowing local verification to start
Metadata Extraction and Normalization
Given a supported source (uploaded file or public URL) has been accepted When metadata extraction runs Then duration (in HH:MM:SS), container, primary audio codec, video codec (if present), resolution (if video), bitrate, and detected language (if available) are displayed Given metadata extraction partially fails (e.g., language not detectable) When results are returned Then available fields are shown and missing fields are labeled as "Unavailable" without blocking verification Given the source has multiple audio tracks When metadata is extracted Then the default track is identified and displayed, with a note of additional tracks
Malware/Virus Scan Gatekeeping (Uploads Only)
Given I upload any file When the antivirus scan runs before further processing Then the UI shows a Scanning stage and blocks hashing/queuing until the scan passes Given the scan detects malware or the scanner errors When the result is received Then the upload is quarantined/rejected, no job is created, and I see an error "Security scan failed" with a support code and remediation guidance Given the scan passes When processing continues Then the flow proceeds to hashing and metadata extraction without re-uploading the file
Preliminary Hashing and Idempotent Queue Routing
Given an upload has passed validation and scanning When preliminary hashing runs Then a SHA-256 hash and file size in bytes are computed and displayed to the user Given a file with an identical SHA-256 hash has an active or completed verification job within the deduplication window When I attempt to submit Then no duplicate job is created; I am linked to the existing job and informed that deduplication was applied Given queue infrastructure is operational When a new job is submitted Then exactly one job is enqueued and its status transitions to Queued within 2 seconds; on transient queue failure, the system retries up to the configured limit and surfaces a retry option on persistent failure
Progress Indicators, Accessibility, and Error Messaging (No Login)
Given any supported intake path (link or upload) is in progress When stages advance Then the UI shows a stepwise timeline (Uploading, Scanning, Hashing, Metadata, Queued) with real-time updates and an accessible ARIA-live region for screen readers Given an operation fails at any stage When an error occurs Then an inline error is displayed with a human-readable message, a unique error code, and an actionable next step; the state allows retry without page refresh Given I am not logged in When I access the portal Then I can initiate verification without authentication, and no PII or workspace data is exposed in the UI or network responses
Tamper-evident Artifact Hashing and Signature
"As a compliance officer, I want artifacts to be tamper-evident via hashing and signatures so that I can trust that verification results reflect the original generated outputs."
Description

Deterministic hashing (e.g., SHA-256) and optional digital signatures for all verification-relevant artifacts, including transcripts, caption files, audio segments, highlight clip manifests, and summary exports. Hashes and signing metadata (algorithm, created-at, signer key ID) are recorded with immutable versioning and embedded into exports where possible (e.g., sidecar JSON, SRT comments) for later validation. Backward-compatible fallbacks handle legacy artifacts without signatures. This requirement ensures the verifier can prove that inputs have not been altered between generation and verification, strengthening trust in pass/fail results and provenance displays.

Acceptance Criteria
Deterministic Hash Generation Across Environments
Given any verification-relevant artifact bytes When hashed with SHA-256 Then the resulting digest is identical for identical bytes across OS, language, and runtime. Given the artifact bytes change by a single byte When hashed Then the resulting digest is different and no collision is reported. Given a batch containing transcript, caption, audio segment, highlight manifest, and summary export When hashed Then each digest and metadata (algorithm="SHA-256", createdAt ISO-8601 UTC, artifactType) are persisted for that version without mutation.
Optional Digital Signature with Metadata Recording
Given signing is enabled and a signer key is configured When an artifact version is finalized Then a detached digital signature is created using the configured algorithm and stored with signature, algorithm, signerKeyId, and createdAt. Given the corresponding public key is available to the verifier When verifying the artifact Then signatureValid=true and result includes signerKeyId and createdAt. Given the signature or its metadata is missing or altered When verifying Then signatureValid=false and the result includes reason="signature_invalid_or_missing".
Hash and Signature Embedded in Exported Artifacts
Given an artifact is exported as SRT, VTT, JSON, or with a sidecar JSON When export completes Then the artifact hash and signing metadata (algorithm, createdAt, signerKeyId, signature if present) are embedded as comments for SRT/VTT, as top-level metadata for JSON, or as a separate sidecar file where comments are unsupported. Given only the exported file(s) are available (no backend access) When the verifier parses them Then it can extract hash and signing metadata to perform validation. Given a standard player opens the SRT/VTT export When rendering Then captions display without rendering or breaking due to embedded metadata.
Immutable Versioning and Provenance Chain Recording
Given an artifact is updated When saved Then a new immutable version is created with a new hash and metadata; prior versions remain readable and unmodified. Given an artifact has multiple versions When viewed in the verifier Then the provenance chain lists versions in order with versionId, createdAt, hash, and signerKeyId (if signed). Given an attempt is made to modify a stored version in place When processed Then the operation is rejected and guidance to create a new version is returned.
Legacy Unsigned Artifact Verification Fallback
Given a legacy artifact lacks signature metadata When verifying Then the system performs a hash match against the registry and reports integrity=pass and signatureStatus="unsigned". Given a legacy export lacks embedded metadata but a sidecar JSON is provided When verifying Then the verifier uses the sidecar to validate and reports signatureStatus="unsigned". Given neither registry nor sidecar metadata exists When verifying Then result=status="Unverifiable" with reason="missing_metadata" and no Pass is reported.
Public and Offline Verifier Validates Artifacts Without Login
Given a third party uses the public portal without authentication When they paste a ClipSpark artifact link Then the verifier retrieves required data, computes the hash, validates signature (if present), and displays Pass/Fail with chain details. Given the offline verifier is used and a file is drag-dropped When verifying Then all checks complete locally without network calls and results match those of the online verifier for the same inputs. Given verification completes When results are displayed Then no workspace-restricted data is shown; only hash/signature metadata, pass/fail status, and provenance chain are presented.
Mismatch Detection and Clear Failure Reporting
Given the artifact bytes do not match the stored hash When verifying Then status="Fail" and the response includes expectedHash, actualHash, and mismatchReason="hash_mismatch". Given a signed artifact with an invalid signature When verifying Then status="Fail", signatureValid=false, and reason="signature_invalid" are returned. Given a structured transcript or caption differs from the recorded version When verifying Then the report includes the index of the first mismatched cue/line when parsing succeeds; otherwise a file-level mismatch is reported.
Quote Match and Timecode Verification (Pass/Fail)
"As a journalist, I want to input a quote and receive a pass/fail with precise timestamps so that I can confirm accuracy before publishing."
Description

A verification engine that accepts a quoted text snippet and optional expected time range, performs normalized and language-aware matching against the transcript/captions, and returns a pass/fail outcome with confidence, exact timestamps, and surrounding context. The matcher handles punctuation and case normalization, minor OCR/ASR variances, diacritics, and configurable tolerance windows. Results include linked evidence (audio/text excerpt) and provide deterministic output given the same inputs and artifact versions. This engine integrates with the portal UI, intake layer, and hashing subsystem to ensure reproducible and auditable verification outcomes.

Acceptance Criteria
Exact Quote Match within Expected Time Window
Given a transcript/captions artifact with content hash H that contains the quote Q verbatim at timestamp t And an expected time range [t-Δ, t+Δ] is provided And normalization is enabled with tolerance=0 When the verifier runs against the artifact H with inputs {Q, expectedTimeRange} Then outcome = "Pass" And confidence = 1.00 And returned match timestamps include startTime and endTime that cover Q and lie fully within [t-Δ, t+Δ] And the response includes artifactHash=H, modelVersion, normalizationRulesId, and parameterSnapshot And the text context includes at least 1 full sentence before and after Q And the audio evidence link spans [max(0, startTime-5s), min(mediaEnd, endTime+5s)]
Fuzzy Quote Match with Configurable Tolerance
Given a quote Q′ differing from the transcript by minor OCR/ASR variances (insertions/deletions/substitutions) And tolerance is set to tokenEditDistance <= 10% and diacritics/punctuation/case normalization is enabled And minimumPassConfidence = 0.85 When the verifier runs with inputs {Q′, tolerance, minConfidence} Then outcome = "Pass" if computedConfidence >= 0.85 and tokenEditDistancePct <= 10% And the response includes computedConfidence, tokenEditDistancePct, normalizedMatchedText, rawMatchedText, and mismatchHighlights And timestamps returned correspond to the matched segment in the transcript within ±0.25s of the caption boundaries
Mismatch Handling and Fail Outcome
Given a quote Q that does not appear in the transcript within the configured tolerance Or the best candidate lies outside an expected time range by more than the allowed window When the verifier runs Then outcome = "Fail" And computedConfidence < minConfidence And reasonCodes include one of ["NO_MATCH","OUT_OF_RANGE","BELOW_THRESHOLD"] And topCandidates returns up to 3 nearest candidates with similarityScore, startTime, endTime, and reason for rejection And no audio snippet is generated; evidence contains only candidate excerpts and diagnostics And HTTP status = 200 for a valid verification request, with failure indicated solely in the payload
Deterministic and Reproducible Output
Given identical inputs {quote, expectedTimeRange, tolerance, minConfidence} and identical artifacts {transcriptHash H, mediaHash M, modelVersion V, normalizationRulesId R} When the verifier is executed multiple times in both portal and offline modes Then the serialized JSON result (excluding generatedAt timestamp) is byte-for-byte identical across runs And list orderings (candidates, highlights, chainDetails) are stable and sorted by deterministic keys {similarity desc, startTime asc, text asc} And changing any input parameter or artifact/version produces a result with updated parameterSnapshot and hashes, making differences auditable
Language-Aware Normalization and Multilingual Support
Given quotes and transcripts that may include diacritics, punctuation variants, case differences, and right-to-left scripts When language-aware normalization is applied Then "café" matches "cafe", "NAÏVE" matches "naive", and RTL scripts match respecting grapheme boundaries and directionality And tokenization respects language-specific rules; matches do not split grapheme clusters And the response includes detectedLocale for the matched segment and normalizationSteps applied
Evidence Delivery and Context Linking
Given a Pass outcome When evidence is generated Then text evidence includes the matched quote highlighted and at least 1 preceding and 1 following sentence And audio evidence includes a clip of 10s around the match [start-5s, end+5s], clipped to media bounds, with format=mp3 and sampleRate >= 44.1kHz And portal responses include signed URLs valid >= 15 minutes; offline responses include local file paths or packaged evidence assets And chainDetails include {artifactHash, mediaHash, transcriptSegmentHash, modelVersion, normalizationRulesId, tolerance, minConfidence, algorithmId}
Public Portal and Offline Verifier Integration & Performance
Given a user pastes a public link or drags a supported media/transcript file into the Open Verifier portal When the verification is submitted Then the portal displays outcome (Pass/Fail), confidence, timestamps, context, mismatch alerts, and chain details in a read-only view, without requiring login And unsupported or missing inputs yield a structured error with code and remediation (e.g., MISSING_TRANSCRIPT, UNSUPPORTED_FORMAT) And the offline CLI accepts equivalent inputs and produces an identical result schema And for transcripts up to 200k characters, 95th percentile verification latency <= 2s on reference hardware (4 vCPU, 8 GB RAM), 99th percentile <= 5s And no network access is required for offline mode; results match portal for identical artifacts and parameters
Provenance Chain Visualization
"As an external stakeholder, I want to see the processing chain and versions so that I understand how a quoted clip or caption was produced."
Description

An interactive, read-only view that depicts the chain of custody from the original source media through transcription, edits, highlight creation, and export. Each node shows artifact type, version, hash/signature, tool version, timestamps, and relevant settings (e.g., ASR model, language). Users can expand nodes to see detailed metadata and link to downloadable evidence files. This visualization integrates with the hashing/signature store and processing logs to provide transparent, end-to-end traceability that explains how a verified quote was derived.

Acceptance Criteria
Public Read-Only Chain Rendering via Verification Portal
Given a valid public verification URL for a ClipSpark quote or artifact, When the page loads in a modern browser without authentication, Then the provenance chain renders in read-only mode with no edit or delete controls. Given the chain has multiple stages from source media through export, When rendered, Then the top-level path includes Source Media, Transcription, Edits, Highlight(s), and Export nodes in chronological order. Given the page loads, When a request to the verification API fails, Then a user-facing error state is shown with a retry control and no partial/mutable UI is displayed. Given an invalid or expired URL token, When accessed, Then a "Verification Link Invalid" page is shown with no chain data leakage and HTTP 404 status.
Node Metadata Completeness and Accuracy
Given any node is visible, When inspected, Then it displays artifact type, artifact version, cryptographic hash (SHA-256) or signature algorithm and value (truncated with copy control), producing tool name and version, created/processed timestamps (ISO 8601, UTC), and relevant settings including ASR model name/version and language where applicable. Given a node value is displayed, When cross-checked against the hashing/signature store and processing logs, Then the displayed values exactly match stored records for that artifact ID. Given timestamps are displayed, When validated, Then they include timezone (UTC) and are consistent across parent/child nodes within a 100 ms tolerance of processing order.
Expandable Metadata and Evidence Downloads
Given a node has additional metadata, When the user clicks Expand, Then a details panel opens showing full metadata in a structured list without truncation. Given a node references evidence files (e.g., raw logs, JSON manifests, signature files), When the user clicks a Download Evidence link, Then the correct file is downloaded with accurate filename, size, and content-type and the request is authenticated for public-read only. Given an evidence file is missing, When a download is attempted, Then a clear missing-evidence message is shown and the node is marked with a non-blocking Warning state.
Hash and Signature Verification with Mismatch Alerts
Given a node with a stored hash/signature, When verification is executed, Then the system recomputes the hash for the artifact content or verifies the signature against the public key and records a Pass or Fail per node. Given a mismatch is detected at any node, When displayed, Then the node is labeled Fail with a reason code (e.g., HASH_MISMATCH, BAD_SIGNATURE, MISSING_KEY) and the chain above that node is visually flagged. Given successful verification across all nodes, When displayed, Then a global Verified banner is shown with the verification algorithm(s) and timestamp.
Quote-to-Chain Traceability Path Highlighting
Given a verified quote with start and end timestamps, When the chain is viewed, Then the unique path from Source Media to the Highlight/Export artifact containing the quote is visually highlighted. Given the quote is selected, When the user clicks "View Context", Then transcript segments and media timecodes that produced the quote are shown and align with the highlight node's segment boundaries within ±1 frame for video or ±40 ms for audio. Given multiple highlights exist, When the quote is selected, Then only the path that produced that specific quote is highlighted and others are dimmed.
Offline Verifier Import and Parity with Portal Results
Given the offline verifier is launched with no network, When a user drags a ClipSpark evidence bundle (.zip or .cs-evidence) into the window, Then the provenance chain reconstructs locally and verification executes without external API calls. Given the same evidence bundle is verified in the portal and offline, When results are compared, Then node Pass/Fail outcomes and displayed metadata are identical, and a results parity checksum matches across both environments. Given a user drags only a source media file without a bundle, When processed offline, Then the verifier reports that provenance is incomplete and prompts for a bundle, without attempting to upload or transmit the file.
Performance, Scalability, and Accessibility Compliance
Given a chain with up to 200 nodes and average metadata size of 4 KB per node, When loaded on a mid-tier laptop (4-core CPU, 8 GB RAM) over a 20 Mbps connection, Then initial render completes within 2 seconds and interactions (pan/zoom/expand) respond within 100 ms. Given the visualization is used via keyboard only, When navigating nodes, Then all interactive elements are focusable in a logical order and operable with Enter/Space, meeting WCAG 2.1 AA. Given a user with a screen reader, When the chain canvas is focused, Then nodes expose accessible names and statuses (e.g., "Transcript v2, Verified") and relationships, and contrast ratios for text/badges meet 4.5:1.
Mismatch Alerts and Troubleshooting Diagnostics
"As a fact-checker, I want clear mismatch alerts with diagnostics so that I can resolve discrepancies or confidently flag issues for follow-up."
Description

Automated detection and clear surfacing of mismatch scenarios such as no match found, low confidence, time drift, sample rate or encoding discrepancies, and language mismatches. The portal displays human-readable alerts with actionable diagnostics (e.g., suggested normalization, checking alternate language tracks, verifying correct artifact version) and links to relevant evidence. Structured diagnostic codes are emitted in the API for programmatic consumers. This reduces support burden and helps third parties resolve discrepancies quickly or escalate with precise context.

Acceptance Criteria
No Match Found Alert in Public Portal
Given a public verifier session with a valid source (URL or file) and a submitted quote, When all candidate alignments score below the pass threshold (default 0.75) and the top score is below the no-match cutoff (default 0.30), Then the portal displays a visible No Match Found alert with severity=error and diagnostic code=CS-MISMATCH-NO_MATCH. And the alert includes at least two actionable steps: verify the correct artifact/version and broaden the quote or time window. And the page presents links to relevant evidence: an empty matches list and the top 3 nearest segments with timestamps and scores. And the result header clearly marks pass=false. And the API response payload includes code=CS-MISMATCH-NO_MATCH, pass=false, topScores (array of score,timestamp), and evidence=[] in a stable schema.
Low Confidence Match Warning and Threshold Disclosure
Given a verifier session that finds at least one alignment with score ≥ low-confidence floor (default 0.50) and < pass threshold (default 0.75), When results are rendered, Then the portal displays a Low Confidence warning with severity=warning and diagnostic code=CS-MISMATCH-LOW_CONF. And the warning discloses the best confidence score (to 2 decimals) and the active pass threshold value. And the UI provides a link to the matched segment at its start timestamp and a preview of ±5 seconds around it. And the alert lists at least one remediation: increase quote length, check alternate language tracks, or normalize audio. And the API response includes code=CS-MISMATCH-LOW_CONF, bestScore, threshold, matchedTimestamp, and pass=false.
Time Drift Detection with Suggested Offset
Given the verifier computes anchor points between the quote and media, When the median absolute offset exceeds the drift tolerance (default 0.50s), Then the portal displays a Time Drift Detected alert with severity=warning and diagnostic code=CS-MISMATCH-TIME_DRIFT. And the alert shows the measured median offset in seconds and the suggested global offset (rounded to 0.1s). And the UI links to at least three anchor evidence points (timestamp pairs before/after correction) if available. And the alert includes remediation to re-export or apply the suggested offset during verification. And the API response includes code=CS-MISMATCH-TIME_DRIFT, medianOffsetSeconds, suggestedOffsetSeconds, anchorCount, and pass=false.
Sample Rate or Encoding Discrepancy Diagnostics
Given the verifier inspects media metadata, When the detected sample rate or codec does not match the normalization targets (default 48kHz, PCM 16-bit mono) or declared transcript parameters, Then the portal displays an Encoding Mismatch alert with severity=warning and diagnostic code=CS-MISMATCH-ENCODING. And the alert lists detected vs expected parameters (sampleRateHz, channels, bitDepth if known, codec/container). And the alert provides remediation steps including suggested normalization targets and a link to docs. And evidence includes a collapsible stream info panel sourced from the file or URL probe. And the API response includes code=CS-MISMATCH-ENCODING, detected (object), expected (object), and pass=conditional (false if alignment fails due to encoding).
Language Mismatch and Alternate Track Selection
Given auto language detection runs on the provided media, When the top detected language (probability ≥ 0.80) differs from the declared language or an alternate audio track yields a higher alignment score, Then the portal displays a Language Mismatch alert with severity=warning and diagnostic code=CS-MISMATCH-LANG. And the alert lists detected language probabilities for the top 3 languages. And the UI presents available audio tracks with detected languages and allows switching tracks without login. And upon selecting an alternate track, the verifier re-runs and updates results inline, preserving an audit trail of the change. And the API response includes code=CS-MISMATCH-LANG, detectedLanguage, declaredLanguage (if provided), availableTracks[], recommendedTrackId (if any), and pass=conditional.
Artifact Version or Hash Mismatch
Given the verification request includes or resolves to an expected artifact identity (e.g., hash/ETag/versionId), When the provided source file or URL resolves to a different identity, Then the portal displays an Artifact Version Mismatch alert with severity=error and diagnostic code=CS-MISMATCH-VERSION. And the alert shows expected and actual identifiers and the acquisition timestamps if available. And the alert offers remediation to fetch or upload the correct artifact version and links to the expected artifact if accessible publicly. And the result is marked pass=false until the correct version is verified. And the API response includes code=CS-MISMATCH-VERSION, expectedId, actualId, evidence (identity method), and pass=false.
Offline Verifier Parity and Deterministic Output
Given the offline verifier is used in an environment without internet connectivity, When a user drags the same media and submits the same quote as in a prior online session, Then the offline results contain the same diagnostic codes, severities, and suggested remediations for the same inputs. And all alerts render without requiring authentication or external calls. And the offline verifier writes a local JSON report adhering to the same API schema (including code, message, details, evidence) and a pass flag. And any referenced evidence (e.g., snippet timestamps) is included or cached locally so links resolve to local previews. And a checksum of inputs is recorded to assert parity between online and offline runs.
Offline Verifier (CLI/SDK)
"As a security-conscious user, I want an offline verifier so that I can validate artifacts in air-gapped or restricted environments without sending data to external services."
Description

A cross-platform, network-optional verifier distributed as a CLI and embeddable SDK that performs the same deterministic checks as the portal using local inputs. It accepts media and artifact files, validates hashes/signatures, runs quote matching, and outputs both human-readable and JSON reports. The tool includes reproducible builds, package signatures, and comprehensive documentation, enabling verification in air-gapped or high-security environments. This extends trust beyond the web portal and supports integration into CI pipelines or newsroom workflows.

Acceptance Criteria
Air-Gapped CLI Verification
Given a host with outbound network connectivity disabled When the user runs clipspark-verify against local media and artifact files Then all verification checks complete without any network calls and the log notes "offline mode: enabled" Given only local file paths are provided When verification succeeds Then the process exits with code 0 and the summary reports all checks passed Given an input path that does not exist When the command is executed Then the process exits with code 2 and stderr contains a single-line error including code EINPUT_NOT_FOUND and the missing path
Deterministic Parity with Web Portal
Given the same media and artifact inputs previously verified by the web portal using ruleset version X.Y.Z When the CLI runs with ruleset version X.Y.Z Then the overall Pass/Fail result and each per-check status are identical to the portal's results Given identical inputs and configuration When the CLI is run twice Then the generated JSON reports are byte-for-byte identical and include fields rulesetVersion and toolCommit Given the portal's exported JSON and the CLI's JSON for the same inputs When compared ignoring the generatedAt timestamp field only Then the documents are deeply equal
Dual Report Outputs
Given the CLI is invoked with default options When verification completes Then a human-readable report is printed to stdout including sections: Summary, Checks, Chain Details, and Mismatch Alerts Given the flag --json out.json is provided When verification completes Then a JSON report is written to out.json conforming to the published JSON Schema (declaring $schema and schemaVersion) and validates with no errors Given the flag --json - is provided and stdout is non-TTY When verification completes Then the JSON report is streamed to stdout as valid UTF-8 with no ANSI color codes
Cryptographic Validation of Hashes and Signatures
Given an artifact and an expected SHA-256 digest provided via --hash sha256:<digest> When the CLI runs Then it computes the artifact's SHA-256 and marks the check Pass when equal and Fail when different, including expected and computed digests in the report Given a detached Ed25519 signature file and a matching public key When the CLI is run with --sig <sigfile> --signing-key <pubkey> Then the signature verification result is reported as Pass when valid and Fail when invalid Given an RSA-2048 signature with SHA-256 and the correct public key When the artifact is altered Then the signature check Fails and the overall result is Fail
Quote Matching Accuracy and Timestamp Precision
Given a video and its corresponding artifact containing quotes When the CLI runs Then each matched quote in the JSON report includes fields: text, startMs, endMs, and confidence Given the same inputs verified by the web portal When comparing quote matches Then the set of matched quotes and their timestamps are identical to the portal within ±50ms tolerance and the texts match after case/whitespace normalization Given a quote that cannot be matched When verification completes Then the report includes a Mismatch Alert with a reason code "no_match" and a reference to the searched time window
SDK Integration in CI Pipeline
Given a CI job with egress disabled When the CLI is invoked in a pipeline step against provided inputs Then the step exits with code 1 if any verification check fails and 0 only if all checks pass Given the SDK is used within a CI task When verify(inputs, { offline: true }) is called Then it returns a result that conforms exactly to the CLI JSON schema and performs no network calls Given stdout is non-TTY in CI When the CLI runs with --quiet Then no progress spinners or ANSI color codes are emitted and only the final summary and requested JSON are printed
Reproducible Builds and Package Signatures
Given the documented build instructions for release vX.Y.Z When the release is rebuilt in the specified clean environment Then the resulting CLI binary's SHA-256 matches the published checksum exactly Given the release artifacts and the published maintainer public keys When verifying detached signatures for the artifacts Then signature verification succeeds for official releases and fails for any tampered artifact Given the documentation site When reviewed Then it contains and renders the following sections with at least one working example each: Installation, Offline Usage, JSON Schema Reference, CLI Flags, SDK API, CI Examples, Reproducible Builds, Signature Verification

Redaction Shield

Redact PII or privileged text while preserving integrity via selective-disclosure hashing (Merkle proofs). Share redacted exhibits that still verify against the original audio, meeting privacy requirements without weakening evidentiary confidence.

Requirements

Automated PII & Privileged Content Detection
"As a legal/compliance reviewer, I want automatic detection of PII and privileged content so that I can quickly protect sensitive information without missing anything."
Description

Automatically identify and label personally identifiable information (PII) and privileged text within transcripts aligned to audio timestamps using a hybrid ML and rule-based detector; supports configurable entity types (e.g., names, emails, phone numbers, SSNs, financial data, health data, attorney–client), multilingual models, confidence thresholds, custom dictionaries and regexes, and speaker-aware detection; produces precise, merge-safe spans ready for redaction across transcript, captions, audio (bleep/mute), and video (blur/box); runs in streaming mode for long recordings; persists annotations as first-class objects and propagates them through editing, exports, and APIs to reduce manual effort and enforce privacy at scale.

Acceptance Criteria
Streaming PII detection during live transcription
- Given a real-time stream of 2-hour audio with interim ASR hypotheses enabled, when tokens are received, then PII/privileged annotations for those tokens are emitted within 1,000 ms at P95 and 2,500 ms at P99. - Given ASR revises prior text, when a previously annotated span changes, then the obsolete annotation is withdrawn and a corrected annotation replaces it within 500 ms, with no duplicate IDs. - Given a transient network gap of up to 5,000 ms, when streaming resumes, then detection backfills for missed audio and timestamps remain monotonic and gap-aware. - Given a per-project confidence threshold of 0.80, when detection scores are below threshold, then no annotation is emitted; when above, annotation includes score and model_origin fields.
Configurable entity types, thresholds, and custom patterns
- Given a project config enabling {NAME, EMAIL, PHONE, SSN, FINANCIAL, HEALTH, PRIVILEGED} and disabling {ADDRESS}, when detection runs, then only enabled types are emitted. - Given per-entity thresholds Name=0.92, Email=0.50, Phone=0.70, when detection runs, then each type respects its threshold and annotations record threshold_applied. - Given a custom dictionary with ["Acme Blue Plan","Case 19-CR-827"], when those phrases occur, then annotations are emitted with type HEALTH_PLAN and CASE_ID and origin=dictionary. - Given a custom regex VAT_ID:^[A-Z]{2}[0-9]{9}$, when a match occurs, then an annotation is emitted with type VAT_ID and origin=regex, even if language model confidence is low. - Given config updated via API, when a new job starts, then the latest versioned config id is logged in each annotation.
Multilingual and code-switching PII detection
- Given a transcript containing English and Spanish segments, when emails, phone numbers, and names with diacritics appear, then annotations are emitted with correct locale-normalized values and language tags (en, es). - Given a benchmark of 1,000 labeled spans across supported languages, when batch evaluation runs, then macro precision >= 0.90 and macro recall >= 0.85; for code-switching subsets, recall >= 0.83. - Given unsupported language text (e.g., xx), when detection confidence < 0.50 and no rule-based matches occur, then no annotations are emitted and a language_unsupported flag is logged once per segment. - Given CJK text without whitespace, when names and IDs are detected, then char_start/char_end and start_time_ms/end_time_ms are accurate within +/- 20 ms of human labels.
Speaker-aware and context-sensitive detection
- Given diarized speakers with role tags {Attorney, Client}, when attorney–client privileged phrases occur across alternating turns, then a PRIVILEGED segment annotation spans from first qualifying attorney utterance start to last client response end within a 120-second window. - Given a speaker says "my SSN is 123-45-6789", when the SSN is detected, then annotation.assignee_speaker_id equals that speaker and the span does not cross into adjacent speakers. - Given a greeting "Hi John" from Speaker A, when the name is detected, then the NAME annotation is attributed to Speaker A's utterance with correct local offsets. - Given overlapping mentions of different types in one utterance, when detection runs, then both are emitted with deterministic ordering by start_time_ms then length desc.
Precise, merge-safe spans with timestamp alignment
- Given tokenized utterances with timestamps, when annotations are created, then each includes char_start, char_end, token_start, token_end, start_time_ms, end_time_ms with start_time_ms < end_time_ms and both within the utterance bounds. - Given overlapping or nested candidates of the same type, when spans are finalized, then the longest non-overlapping span is kept and adjacent same-type spans with gaps <= 50 ms are merged. - Given user edits (cut, split, join, insert text) not affecting audio, when the document is saved, then annotation char offsets rebase deterministically and start/end_time_ms remain unchanged with drift <= 30 ms. - Given re-segmentation that moves tokens between caption lines, when captions are regenerated, then spans do not cross caption boundaries unless tokens do, and caption files validate against SRT/WebVTT parsers.
Redaction-ready outputs for transcript, captions, audio, and video
- Given accepted annotations, when one-click redaction is applied, then transcript text within spans is replaced with [REDACTED:<TYPE>] and original timestamps remain unchanged. - Given two spans separated by < 200 ms, when audio redaction runs, then they are merged and a single mute/bleep is applied with 10 ms padding on each side; audio duration is unchanged and peak levels remain within +/-1 dB outside redacted windows. - Given captions (SRT/WebVTT), when redaction runs, then caption payloads reflect [REDACTED:<TYPE>] without breaking timecode syntax; validators report zero errors. - Given video export with burned-in captions enabled, when redaction runs, then a blur box overlays the caption region during redacted intervals with opacity >= 90% and no flicker (>2 fps box changes prohibited).
Persistence and propagation of annotations through edits, exports, and APIs
- Given annotations stored with stable ids and version, when a highlight clip (subset timeline) is created, then annotations fully or partially within the kept range are copied, times re-based to the clip, and source_annotation_id preserved. - Given a user deletes or edits an annotation, when exporting, then only current annotations are included and an audit record with user_id, timestamp, and action is persisted. - Given export via API and UI, when generating JSON, SRT, VTT, and EDL/XML, then each includes annotations with type, score, start_time_ms, end_time_ms, and speaker_id; schema validates against published JSON Schema and XML schema. - Given project duplication, when the new project is created, then custom configurations (entity enables, thresholds, dictionaries, regexes) and existing annotations are present and reference a new project id.
Selective-Disclosure Hashing Engine
"As an evidence recipient or auditor, I want cryptographically verifiable redacted artifacts so that I can trust they match the original without accessing private data."
Description

Compute content-addressed Merkle trees over canonicalized transcript tokens and time-sliced audio frames to enable selective disclosure that preserves verifiability after redaction; generate and store a versioned root hash per source asset, maintain deterministic serialization, and support proof construction for any shared, unredacted span while keeping redacted nodes as blinded commitments; include algorithm identifiers (e.g., SHA-256), chunking parameters, and alignment metadata to guarantee reproducible proofs across platforms; persist roots immutably and expose them for verification without revealing original content.

Acceptance Criteria
Deterministic Merkle Root Reproducibility Across Platforms
Given a source asset (transcript and audio) and parameters {algorithmId: "SHA-256", chunking: {tokenSize: 1024, frameSizeMs: 20}, alignment: "v1" When the hashing engine constructs Merkle trees on Windows (Node.js 20), Linux (Python 3.11), and macOS (Rust CLI), each run 5 times Then the transcript tree root, audio tree root, and combined root are identical across platforms and runs And the canonicalized leaf serialization bytes are identical across runs And each root is a 32-byte digest exposed as lowercase hex of length 64
Immutable Versioned Root Persistence and Public Exposure Without Content
Given an asset is hashed producing root R with version "v1" and metadata {assetId, algorithmId, chunking, alignment, timestamp} When persisting R Then R and its metadata are stored immutably; subsequent attempts to overwrite the same (assetId, version) are rejected with HTTP 409 And R is retrievable via GET /verify/{R} exposing only {root, version, algorithmId, chunking, alignment, timestamp} And no original content bytes are returned in the response And an append-only audit record is written with {actor, action, timestamp}
Selective Disclosure Proof for Unredacted Transcript Span
Given a requested unredacted transcript span [startToken, endToken] with associated time span [tStart, tEnd] When a selective-disclosure proof is generated for the span Then the proof verifies successfully against the stored root using the reference verifier And the proof includes only the disclosed leaves and necessary sibling hashes plus {algorithmId, chunking, alignment} And no undisclosed leaf values are present And for a 10k-token transcript, the proof size for a 500-token span is <= 64 KB
Redacted Nodes Are Blinded Commitments
Given a redaction mask that hides designated tokens and audio frames When constructing a proof that traverses redacted regions Then all redacted leaves and internal nodes are represented only by their hash commitments (no plaintext tokens or audio samples) And verification against the root succeeds without requiring redacted preimages And attempting to recover redacted content from the proof yields zero bytes of original content and no hashes shorter than the algorithm digest length
Token–Audio Alignment Integrity in Proofs
Given canonical tokenization and audio sliced into 20 ms frames with alignment metadata mapping tokens to frame indices When generating a proof for a token span Then the alignment metadata included in the proof maps each disclosed token to its covering frame range And the maximum absolute difference between token timestamps and frame boundaries in the proof is <= 20 ms And an independent verifier recomputes the mapping and obtains the same alignment for all disclosed tokens
Algorithm and Parameter Versioning with Backward Compatibility
Given root R1 produced with parameters {version: "v1", algorithmId: "SHA-256", chunkSizeTokens: 1024} and root R2 produced with {version: "v2", algorithmId: "SHA-256", chunkSizeTokens: 2048} When verifying a v1 proof against R2 Then verification fails with error code CODE_PARAM_MISMATCH And verifying the same v1 proof against R1 succeeds And requesting hashing with v2 parameters creates R2 without mutating R1 or its metadata
Tamper Detection and Failure Signaling
Given a valid proof P for root R When one bit of P or of the disclosed leaf payload is flipped Then verification fails with error code CODE_INTEGRITY_FAIL And verifying P against any root R' != R fails with CODE_ROOT_MISMATCH And requesting verification for an unknown root returns HTTP 404
Redaction Review Timeline Editor
"As an editor, I want an intuitive timeline and transcript UI to review and refine redactions so that I can ensure accuracy before sharing."
Description

Provide an interactive timeline and transcript editor to review detections, adjust spans, add manual redactions, and preview outputs across modalities; offer batch actions, keyboard shortcuts, zoomable waveform, side-by-side original versus redacted views, undo/redo, conflict resolution for overlapping spans, and safe-preview playback; ensure edits propagate consistently to captions, highlight clips, and exports while preserving timestamps and speaker labels.

Acceptance Criteria
Adjust and Confirm Auto-Detected Redaction Spans
- Given auto-detected redaction spans are visible in both timeline and transcript with labels and timestamps, When the user drags start or end handles on the timeline or edits timestamps numerically, Then the span updates and both views stay synchronized within 50 ms. - Given a span is adjusted, When playback crosses the adjusted boundaries, Then the safe-preview applies redaction exactly at the new boundaries with <=10 ms deviation. - Given adjusted spans, When the project is saved and reloaded, Then the adjustments persist identically (start/end within 1 ms of saved values) and labels remain unchanged. - Given snap-to-word is enabled, When a span endpoint is moved, Then it snaps to the nearest token boundary within 20 ms and the snapped token is displayed. - Given a span is adjusted across speaker turns, When saved, Then speaker labels remain attached to their respective unredacted tokens and are not reassigned.
Add Manual Redactions via Transcript and Timeline
- Given the transcript view, When the user selects a word or multi-word range and presses R or clicks Redact, Then a redaction span is created covering the exact token timecodes and labeled with the chosen PII type. - Given the timeline view, When the user click-drags to draw a span and selects a PII label, Then a matching transcript highlight is created and the span inherits the correct speaker label. - Given a manual redaction overlaps an auto-detected one, When saving, Then the conflict resolution flow is invoked before persistence. - Given a manual redaction is created, When undo is invoked, Then the span and its effects on captions and highlights are reverted; When redo is invoked, Then they are restored. - Given a manual redaction is created, When safe-preview is played, Then the redaction is applied in audio, video, and captions exactly at the span boundaries.
Propagate Edits to Captions, Highlights, and Exports
- Given any span is created, edited, or deleted, When generating captions (SRT/VTT), Then redacted tokens are replaced with [REDACTED] or bleep markers and timestamps align with adjacent unredacted tokens with <=10 ms drift. - Given highlight clip generation, When redaction spans exist, Then video/audio segments within spans are muted and faces/regions are blurred; on-screen captions omit or mask redacted content. - Given export to MP4, WAV, and JSON annotations, When spans are modified, Then exports reflect the latest state and include a machine-readable redaction map with span IDs, types, and start/end times. - Given edits intersect speaker turns, When outputs are generated, Then speaker labels for unredacted content remain unchanged and correctly ordered. - Given a propagation failure occurs, When exporting, Then the user is shown a blocking error listing span IDs and reasons; no partial export is produced.
Conflict Resolution for Overlapping Redaction Spans
- Given two spans overlap or abut, When the user attempts to save, Then a resolver presents options: Merge (union), Split at overlap, or Keep both with priority; default is Merge. - Given Merge is selected, When applied, Then exactly one span exists over the unioned time range and the most-sensitive PII label prevails. - Given Split is selected, When applied, Then spans are split so no time sample is covered by more than one active span; lineage is recorded in the audit trail. - Given Keep both with priority is selected, When previewing/ exporting, Then the higher-priority span governs in the overlap and no double redaction artifacts occur. - Given resolution completes, When validation runs, Then no overlapping spans remain in the persisted model and preview/external outputs pass validation.
Safe-Preview Playback and Side-by-Side View
- Given redacted spans exist, When playing in Redacted Preview, Then audio within spans is muted or bleeped and video regions are blurred; no redacted text renders in captions or transcript overlays. - Given side-by-side mode is enabled, When playback starts, Then Original and Redacted views stay in sync with <=30 ms skew; scrubbing and seeking mirror in both panes. - Given a user clicks a redacted token, When play-from-here is invoked, Then playback starts 100 ms before the token boundary and redaction is enforced at the boundary. - Given captions are enabled, When in Redacted Preview, Then captions replace redacted tokens with [REDACTED] consistently across on-screen captions and the transcript pane. - Given the user toggles between Original and Redacted, When switching during playback, Then playback remains continuous without leakage of redacted audio or text.
Batch Actions, Keyboard Shortcuts, and Undo/Redo
- Given multiple spans are selected via shift-click or lasso, When applying Mark Redacted/Unredacted, Delete, or Change Label, Then the action updates all selected spans and both timeline and transcript remain consistent. - Given keyboard shortcuts (R, U, L, Delete, Cmd/Ctrl+Z, Cmd/Ctrl+Shift+Z), When invoked with focus in either pane, Then the corresponding action executes and a tooltip or aria-label exposes the shortcut. - Given a sequence of at least 20 edits, When undo is invoked repeatedly, Then each edit is reversed in correct order across timeline and transcript; When redo is invoked, Then changes are reapplied. - Given an undoable action, When the project is saved and reloaded, Then the current state persists while the undo/redo history is cleared and a banner indicates a new history session. - Given batch delete is performed, When safe-preview is played, Then no references to deleted spans remain in captions, waveform markers, or exports.
Zoomable Waveform and Precise Timestamp Preservation
- Given the user zooms the waveform, When zooming between 50 ms and 30 min scales, Then the viewport centers on the cursor, animations are smooth, and redaction handles remain selectable. - Given snapping is enabled, When adjusting spans at high zoom, Then endpoints snap to the nearest word or frame boundary (per setting) with <=5 ms rounding error. - Given edits are complete, When exporting annotation JSON, Then start and end times for all spans retain millisecond precision and match the internal model exactly. - Given a recording longer than 2 hours, When navigating and zooming, Then input-to-paint latency remains <100 ms and memory usage stays under 500 MB. - Given the user switches zoom levels, When returning to a previous zoom, Then the prior viewport and selection are restored.
Verifiable Redacted Export Packaging
"As a case manager, I want exportable redacted artifacts with embedded proofs so that stakeholders can view and verify them using standard tools."
Description

Export redacted video, audio, captions, and transcripts with embedded selective-disclosure proofs and metadata so recipients can play artifacts in standard players while independently verifying integrity; support MP4 with sidecar JSON proof bundles, WebVTT/SRT with redaction markers, and PDF/JSON transcript packages signed with JWS/COSE; embed source asset identifiers, root hash, hashing algorithm, canonicalization version, timecode mapping, and policy tags; preserve A/V sync, insert [REDACTED] tokens or blurs/bleeps as configured, and enable one-click sharing and download.

Acceptance Criteria
MP4 Export with Sidecar Proof Bundle
Given a source asset with a unique sourceAssetId, configured redaction ranges, and export format MP4 selected When the user initiates export Then the system produces {basename}.mp4 and {basename}.clipspark.proofs.json in the same target location And the MP4 is a valid ISO BMFF file and is decodable without errors by a standards-compliant player And the sidecar JSON contains fields: sourceAssetId, rootHash, hashAlgorithm, canonicalizationVersion, timecodeMapping, policyTags, proofs And for at least one disclosed segment per redacted range, recomputing the canonicalized leaf hash and verifying its Merkle proof against rootHash succeeds And altering any byte in either file causes verification to fail with an integrity error on re-verify
WebVTT/SRT Redaction Markers and Sync
Given export of captions in both WebVTT and SRT is selected When the export completes Then {basename}.vtt and {basename}.srt are created with no parser errors And every cue overlapping a redacted interval has its text replaced with "[REDACTED]" And no original token text from redacted intervals appears in either file And WebVTT includes a redaction marker per affected cue via a NOTE or cue setting indicating redacted=true And cue timecodes align to the exported MP4 within ±100 ms for start and end times
Signed Transcript Packages (JSON/PDF) with JWS/COSE
Given export of transcripts in JSON and PDF is selected When the export completes Then a transcript JSON file and a transcript PDF are generated And a JWS or COSE signature is produced for the JSON transcript referencing its exact byte content And the JSON signature verifies offline using the configured verification key (kid present) and matches the included rootHash And the PDF is accompanied by a detached JWS/COSE signature over its digest, and verification succeeds And both artifacts (or their package manifest) include: sourceAssetId, rootHash, hashAlgorithm, canonicalizationVersion, timecodeMapping, policyTags
A/V Sync Preservation Post-Redaction
Given a source video with audio and captions and configured redaction intervals When the redacted MP4 and captions are exported Then audio-video lip-sync drift relative to source is ≤100 ms across the full duration And caption cue alignment drift relative to the exported audio is ≤100 ms And the exported timecodeMapping is monotonic, has no overlaps, and contains no gaps >50 ms at redaction boundaries
No Residual PII in Redacted Intervals
Given redaction policies (blur for video; bleep or mute for audio; token replacement for text) are configured When the redacted artifacts are exported Then during each redacted interval, audio conforms to policy: if mute, RMS level ≤ -50 dBFS; if bleep, a tone replaces content with original speech attenuated by ≥40 dB And video within each redacted interval is visually obfuscated per policy over 100% of the intended area for the full interval duration And captions/transcripts show "[REDACTED]" with no original tokens present within redacted spans And a ±50 ms guard band around each redacted interval contains no intelligible original content in audio, video, or text
One-Click Share and Download Packaging
Given the user selects One-Click Share or Download for the redacted export When packaging completes Then a shareable link or a single ZIP is produced containing: MP4, sidecar proofs JSON, WebVTT, SRT, transcript JSON, transcript PDF, signature files, and a manifest.json And the manifest.json includes: sourceAssetId, rootHash, hashAlgorithm, canonicalizationVersion, timecodeMapping, policyTags, file checksums (algorithm specified) And recipients can stream the MP4 from the share link and independently download all artifacts without authentication if the policy permits And downloading and unpacking the ZIP preserves original filenames and checksums match those listed in manifest.json
Independent Offline Verification of Shared Artifacts
Given a recipient downloads the exported artifacts and the sidecar/manifest When they run the verify procedure offline against the package Then verification completes without network access and returns PASS for unmodified artifacts And intentionally modifying any artifact (e.g., one byte) yields FAIL with a reason indicating the failure type (e.g., MERKLE_PROOF_INVALID, HASH_MISMATCH, METADATA_MISSING) And the verify output reports the algorithm and canonicalizationVersion used and the sourceAssetId and rootHash it validated against
Public Verification Tools & APIs
"As an external reviewer, I want easy-to-use verification tools and APIs so that I can validate redacted artifacts independently and at scale."
Description

Deliver a hosted web verifier, CLI, and SDKs (JavaScript/Python) that validate redacted artifacts against published root hashes by checking Merkle proofs and canonicalization parameters; provide a public API to fetch root hashes and proof bundles by asset ID, plus an embeddable widget for evidence pages; include clear error messaging, verification receipts, and deterministic outputs for auditability; document protocols and provide test vectors to drive external adoption.

Acceptance Criteria
Web Verifier Validates Redacted Artifact Against Published Root Hash
- Given a redacted artifact and a published root hash or asset ID, when the user submits them in the hosted web verifier, then the verifier validates the Merkle proof against the root hash and declared canonicalization parameters and returns Verified=true on success. - On success, the UI displays and offers download of a canonical JSON receipt containing: asset_id, artifact_sha256, root_hash, merkle_scheme, proof_depth, canonicalization_version, verifier_version, verified_at, result="PASS", and receipt_id (hash of the receipt excluding verified_at). - Running the same verification twice with identical inputs yields byte-identical receipt JSON excluding the verified_at field, and the same receipt_id. - On invalid proof, hash mismatch, or canonicalization mismatch, the UI returns result="FAIL", displays error_code and message, and suppresses receipt download.
CLI Verification Produces Deterministic Machine-Readable Receipts
- Given the CLI is invoked with --asset-id and --artifact (or --root-hash and --proof-bundle), when verification succeeds, then exit code is 0 and stdout emits canonical JSON (JCS) receipt with fields: asset_id, artifact_sha256, root_hash, canonicalization_version, merkle_scheme, proof_depth, verifier_version, result="PASS", receipt_id. - When verification fails, exit code is 1, stderr includes error_code and message, and no receipt is written unless --receipt-out is combined with --include-fail, in which case result="FAIL" is present. - With --receipt-out <path>, the receipt is written and its filename defaults to <receipt_id>.json when a directory is provided. - With --quiet, no stdout/stderr is emitted and only the exit code reflects the result.
Public API Serves Root Hashes and Proof Bundles by Asset ID
- GET /v1/assets/{asset_id}/root-hash returns 200 application/json with asset_id, root_hash, canonicalization_version, published_at; returns 404 with error_code="API-NOT-FOUND" for unknown asset. - GET /v1/assets/{asset_id}/proof-bundle returns 200 application/json with asset_id, merkle_scheme, canonicalization_version, artifact_hash_alg, leaf_hash, sibling_hashes[]; returns 404 with error_code="API-NOT-FOUND" for unknown asset. - Responses are deterministic (stable key ordering and types), cacheable with ETag, and documented in OpenAPI with example payloads and error schemas.
JavaScript and Python SDKs Validate Proofs Consistently with Reference
- Given identical artifact bytes and proof bundle, when verify() is invoked in both JS and Python SDKs, then both return verified=true and the same receipt_id for passing vectors. - For failing vectors (invalid sibling hash, wrong root, wrong canonicalization), both return verified=false with identical error_code values. - Both SDKs successfully validate the official test vectors suite (minimum 20 cases) and match the CLI receipt bytes for each case. - SDKs expose a pure function that is deterministic and side-effect free, and are versioned and published with typed interfaces.
Embeddable Verification Widget Shows Live Status on Evidence Pages
- Given a script tag <script src=".../widget.js" data-asset-id="..."></script>, when the page loads, then the widget fetches via the public API and renders PASS/FAIL status, root_hash snippet, and a link to view/download the full receipt. - The widget loads without third-party cookies, respects CSP without requiring unsafe-eval, and ships <50KB gzipped of additional JS. - The widget is accessible (WCAG 2.1 AA for color contrast, focus order, ARIA roles) and responsive across viewport widths 320–1920px. - Network failures show a retryable "Unable to verify" state with error_code and no blocking of host page rendering.
Unified Error Messaging and Codes Across Surfaces
- An error code taxonomy is defined and implemented consistently across Web Verifier, CLI, API, and SDKs (e.g., VS-MISMATCH, VS-CANON-UNSUPPORTED, VS-PROOF-MALFORMED, API-NOT-FOUND, API-RATE-LIMIT). - Each error includes a human-readable message and a docs_url pointing to remediation guidance. - No error payload includes sensitive artifact contents; logs and API responses include a correlation_id for traceability.
Protocol Documentation and Test Vectors Enable External Adoption
- Public docs describe canonicalization rules, Merkle proof format, hashing algorithms, verification algorithm, receipt schema, API endpoints, CLI/SDK usage, and security considerations, each with version numbers. - An open repository publishes test vectors (at least 20 pass and fail cases) with inputs, expected receipts, and a script to verify deterministically via CLI, JS SDK, and Python SDK. - A conformance checklist is provided for external implementers; implementations that pass the vectors produce byte-identical receipts and matching result codes.
Access Control & Secrets Management
"As an organization admin, I want fine-grained access controls and encrypted storage so that originals remain protected while redacted versions are shareable."
Description

Implement role-based access controls, SSO/SAML/OIDC integration, and project-level permissions to restrict viewing and exporting of originals versus redacted artifacts; encrypt originals and proof materials at rest and in transit with KMS-backed keys and per-tenant isolation; provide secure, expiring share links for redacted exhibits, watermarking options, and granular scopes for API tokens to ensure privacy by default.

Acceptance Criteria
RBAC: Project-Level Permissions for Originals vs Redacted
- Given a tenant with roles Admin, Editor, Reviewer, Viewer and projects A and B, when Admin configures permissions so only Admin and Editor can view originals in project A, then Reviewer and Viewer cannot open or download originals from project A and receive 403 ACCESS_DENIED via UI and API. - Given a user is Editor in project A and not a member of project B, when the user lists artifacts in project B, then API returns 404 or 403 with no metadata leakage and UI shows no items. - Given a Viewer in project A, when attempting to export an original via POST /api/exports/originals, then response is 403 and export control in UI is disabled; when exporting a redacted artifact via POST /api/exports/redacted, then response is 202 and export starts. - Given a new project is created, when no explicit permissions are set, then viewing/exporting originals is denied to all roles except Admin by default (privacy-by-default). - Given permissions are updated, when changes are saved, then new rules are enforced across UI and API within 60 seconds.
SSO: SAML/OIDC Role Mapping and Session Controls
- Given SAML 2.0 or OIDC is configured with group-to-role mapping, when a user signs in via the IdP, then the account is created or linked and roles are assigned based on group claims for that session. - Given the IdP assertion lacks required email or group claim, when sign-in occurs, then access is denied and no local user is created. - Given SSO is enabled and local password login is disabled, when a user attempts password login, then login is rejected with 403. - Given an SSO session is active, when 30 minutes of inactivity or 12 hours absolute duration elapse (configurable), then the session is invalidated and re-authentication is required. - Given a user is removed from mapped IdP groups, when the next login is attempted or within 5 minutes of the change, then active sessions are terminated and future access is denied.
Encryption: Per-Tenant KMS Keys for Originals and Proofs
- Given tenant T, when originals, redacted artifacts, and proof materials are stored, then they are encrypted at rest using per-tenant KMS-backed envelope encryption (AES-256-GCM) and cannot be read without T's CMK. - Given client or inter-service connections, when data is transmitted, then TLS 1.2+ is enforced and plaintext connections are rejected. - Given a tenant key rotation is initiated, when rotation completes, then new writes use the new key and existing data remains readable; no downtime occurs during rotation. - Given a request from tenant U to decrypt tenant T objects, then KMS denies decrypt and the request fails with 403; cross-tenant decryption is impossible by policy. - Given backups containing originals or proofs, when stored, then they are encrypted and restorable with integrity checks matching source digests.
Export Controls: Originals Restricted, Redacted Watermarked
- Given a user has scope export:redacted but not export:originals, when exporting an original, then response is 403; when exporting a redacted artifact, then response is 202 and the job produces output. - Given the UI lists an original asset, when the user lacks export:originals, then the export control is hidden or disabled with a Not authorized tooltip. - Given API GET /api/artifacts/{id}?variant=original by an unauthorized user, then response is 403; the same request with variant=redacted by an authorized user returns 200 with Content-Disposition attachment. - Given watermarking is enabled for redacted exports, when an export completes, then the media contains a visible, tamper-resistant watermark including tenant name, user email, timestamp, and share-link ID; originals are never watermarked.
Share Links: Expiring, Scoped Access to Redacted Exhibits
- Given a redacted exhibit, when an owner creates a share link, then a tokenized URL is generated with default expiry of 7 days and configurable range of 1 hour to 90 days; after expiry, requests return 410 Gone. - Given restrict to version is enabled, when the artifact is updated, then the old link loads only the original version and cannot access newer versions. - Given a password is set on the link, when 5 consecutive invalid attempts occur, then the link is locked for 15 minutes; correct password unlocks access. - Given a link is revoked by the owner, when subsequent requests arrive, then they fail within 60 seconds with 410 Gone. - Given a share link is used, then it provides access only to the specified redacted artifact and its verification proofs; it cannot access originals or any other project resources.
API Tokens: Granular Scopes, Project Restrictions, and Rotation
- Given an admin creates a token, when no scopes are selected, then the token has no access; default expiry is 90 days (overridable up to 365 days). - Given a token scoped to read:redacted on project A, when it calls endpoints for originals or any project B resources, then responses are 403 or 404 with no sensitive metadata. - Given token creation, when the secret is displayed once, then only a hashed form is stored; subsequent retrieval shows only a non-sensitive prefix. - Given token rotation, when a new token replaces an old one, then the old token remains valid for 15 minutes overlap and is rejected thereafter. - Given API requests with any token, then TLS is required and plaintext requests are rejected; per-token rate limits are enforced to mitigate abuse.
Audit Trail & Compliance Reporting
"As a compliance officer, I want a complete, tamper-evident audit trail so that I can demonstrate due diligence and satisfy regulatory inquiries."
Description

Record an immutable, append-only audit trail of detection, manual edits, approvals, export events, and proof generation with actor identity, timestamps, and asset/version references; support tamper-evidence via chained hash records and optional external anchoring; provide exportable audit reports (CSV/JSON/PDF), retention and deletion policies, and data-access logs to support GDPR/CCPA requests and legal defensibility.

Acceptance Criteria
Append-Only Audit Logging for Redaction Workflow Events
Given an authenticated user U working on asset A (version V) When the system performs automated PII detection, U makes a manual redaction edit, a reviewer approves, U exports a redacted exhibit, and the system generates a proof Then an audit record is appended for each event with fields: event_type ∈ {detection, manual_edit, approval, export, proof_generation}, actor_id, asset_id, version_id, timestamp (UTC ISO 8601 with milliseconds), record_id (UUIDv4), prev_record_hash (nil for first), record_hash (SHA-256), and metadata_digest And attempts to modify or delete an existing record are rejected with HTTP 409 and no new record is added And per asset/version sequence numbers are strictly increasing without gaps for successful writes And after a simulated crash/restart, the last committed record remains present and no partial/duplicate records exist
Tamper-Evident Hash Chaining and External Anchoring
Given an audit trail with N>=2 records When the chain is verified by recomputing each record_hash from its contents and prev_record_hash Then all record_hash values match and the chain head hash is stable And any byte-level mutation in a past record causes verification to fail at that record and all successors And when external anchoring is enabled, the system anchors the chain head hash at least every 10 minutes or after 100 new records (whichever comes first) and stores an anchoring receipt with anchor_id, service, timestamp, and anchored_hash And a verification API returns anchor status and the receipt for any chain head within 2 seconds p95
Exportable Audit Reports with Filters (CSV/JSON/PDF)
Given an audit trail with records across multiple assets and actors When an admin filters by date range, asset_id, event_type, and actor_id and requests exports as CSV, JSON, and PDF Then each export contains only matching records with fields: record_id, timestamp, event_type, actor_id, asset_id, version_id, record_hash, prev_record_hash, metadata_digest And records are sorted ascending by timestamp and the export includes a count of records and the chain head hash used And CSV is UTF-8 with a header row; JSON is line-delimited (NDJSON) with one JSON object per line; PDF includes a summary page with filter criteria and the chain head hash And exports complete for up to 100000 records within 60 seconds and file checksums (SHA-256) are returned
Data Access Logging for GDPR/CCPA Subject Requests
Given a data subject D with subject_identifier present in assets When any user or service views, searches, exports, or downloads content containing D's data (redacted or unredacted) Then a data_access log record is appended with fields: subject_identifier, actor_id, action, purpose_of_use, legal_basis, asset_id, version_id, timestamp, access_channel, result And when an admin generates a subject access audit for D over a date range in JSON and PDF Then the report includes all and only D-related access events, a summary of counts by action, the chain head hash at generation time, and completes within 30 seconds for up to 50000 events And access to the report endpoint requires admin role and is denied with 403 otherwise
Retention and Deletion Policy Enforcement with Chain Integrity
Given tenant-level policies: audit_log_retention=7y and subject_erasure_window=30d When a verified deletion request for subject D is approved Then personal data in audit payloads linked to D is removed or irreversibly anonymized, and a deletion_tombstone record is appended containing hashes of removed fields, approver_id, reason_code, timestamp, and linkage to affected record_ids And chain verification passes end-to-end before and after deletion with unchanged record_hash values for unaffected records And a deletion certificate (JSON and PDF) is generated with the chain head hash and, if anchored, the anchor receipt And when records exceed retention, retention_tombstone records are appended and expired payloads are excluded from exports while preserving chain continuity
Audit Trail Query API Authorization, Pagination, and Performance
Given an API client with read:audit scope and RBAC limiting visibility to specific assets When the client requests GET /audit?asset_id=A&limit=100&cursor=C Then the response returns only authorized records for asset A, includes next_cursor when more results exist, and enforces limit<=100 And requests without required scope or RBAC permission are rejected with 403 without revealing record existence And p95 latency is <=500 ms for queries returning up to 100 records with server-side pagination and indexes And rate limiting is enforced at 100 requests/min/token with HTTP 429 and a Retry-After header on excess
Proof Generation and Verification Traceability
Given a redacted exhibit E derived from asset A via Redaction Shield When the system generates Merkle proof artifacts linking E to the original audio Then an audit record proof_generation is appended with fields: proof_id, proof_hash, merkle_root, original_media_hash, redacted_media_hash, verifier_version, timestamp And when a verifier replays the proof artifacts retrieved by proof_id Then verification succeeds (true) for unaltered inputs and fails (false) if any artifact or input has been modified And the verification attempt is logged with actor_id, proof_id, timestamp, and outcome

Custody Chain

Maintain a quote-level chain of custody from capture to export with signer identities, timestamps, and environment metadata. Export a signed ledger alongside each exhibit and receive proactive alerts if any step breaks linkage—defensible under scrutiny.

Requirements

Immutable Event Ledger
"As a compliance officer, I want an immutable, signed record of every processing step so that I can prove no tampering occurred."
Description

Establish an append-only, cryptographically linked event ledger that records every state transition from capture through export at quote-level granularity. Each event must include a monotonic sequence, ISO-8601 timestamp synchronized via NTP, actor identity, action type, content and artifact digests (e.g., SHA-256), references to environment metadata, and a digital signature. The ledger must implement hash chaining or a Merkle structure to make tampering evident, support idempotent writes, and enforce strict ordering across distributed services. All pipeline services (capture, transcription, summarization, highlight extraction, review, export) must emit signed events to the ledger service via a reliable message bus with retries and deduplication. Data must be stored with encryption at rest and object lock to prevent modification, enabling defensible, forensic-grade auditability under scrutiny.

Acceptance Criteria
Append-Only and Object-Locked Ledger Enforcement
Given a ledger with existing events for a quote When a client attempts to modify or delete any persisted event Then the operation is rejected (HTTP 403/409), no storage objects change, and an audit record is written Given a valid new event to append When it is written to the ledger Then the write succeeds, the event is stored with encryption at rest enabled and object-lock WORM mode active, and subsequent modification/deletion attempts are denied by the storage layer Given the ledger state before and after a successful append When an integrity scan compares counts and object versions Then the total event count increases by exactly one and never decreases
Event Schema and NTP-Synchronized Timestamp Validation
Given an event submitted by any pipeline service When validating its payload Then it contains quote_id, sequence (integer > previous), ISO-8601 UTC timestamp, NTP offset <= 2s at write time, actor_id, action in {capture, transcription, summarization, highlight_extraction, review, export}, content_digest and artifact_digest as 64-char lowercase hex SHA-256, env_metadata_ref, and a digital signature Given an event with any missing/invalid field, malformed digest, disallowed action, or NTP offset > 2s When processed by the ledger Then the event is rejected with a validation error and is not appended
Hash Chain/Merkle Integrity Verification and Tamper Evidence
Given a contiguous chain of events for a quote When recomputing each event_hash and comparing prev_hash to the prior event's hash over the canonical representation Then for all i>1, events[i].prev_hash equals hash(events[i-1]) and chain verification passes Given a bit-level mutation to any stored event When chain verification runs Then verification fails at the mutated event, the quote is flagged as linkage-broken, and an alert is emitted Given a batch export using a Merkle structure When computing the Merkle root over the exported events Then the root matches the value embedded in the export manifest
Idempotent Writes, Deduplication, and Exactly-Once over the Message Bus
Given the same event (identical idempotency_key and signature) is delivered multiple times due to retries When processed by the ledger Then exactly one ledger entry exists for that idempotency_key, the same sequence and event_hash are returned on each attempt, and duplicates are acknowledged without re-writing Given two distinct events with different idempotency_key for the same quote When processed Then both are appended with unique sequence numbers and are not deduplicated Given at-least-once delivery semantics and a ledger service restart during processing When the service recovers Then the eventual ledger contains no duplicate events for any idempotency_key
Strict Per-Quote Ordering Across Distributed Services
Given concurrent events from multiple services for the same quote arriving out of order When they are processed under load Then the ledger assigns strictly increasing per-quote sequence numbers with no gaps or duplicates and persists them in that order regardless of arrival time Given an event with a timestamp older than the latest committed event for the quote When it arrives Then it is assigned the next sequence number (not inserted retroactively), and the hash chain remains valid
Pipeline Services Emit Signed Events with Actor Identity and Environment Metadata
Given each pipeline stage (capture, transcription, summarization, highlight extraction, review, export) completes for a quote When the stage finishes Then a signed event containing actor_id, action type, and env_metadata_ref is published to the bus; the ledger verifies the signature against the registered public key for that service and appends the event Given an event with an unverifiable signature or unknown actor_id When processed Then the ledger rejects the event, records the failure reason, and emits an alert Given an env_metadata_ref on an incoming event When resolving the reference during append Then the metadata object exists and is atomically associated; if it does not exist, the append fails without partial writes
Export Signed Ledger and Offline Verification with Proactive Linkage Alerts
Given a user exports an exhibit for a quote When export completes Then a digitally signed ledger file containing the full event chain and environment metadata references is generated and exported alongside the media artifacts Given the exported package and the public verification keys When verified offline Then all signatures validate, all content/artifact digests match the exported artifacts, and the hash chain or Merkle proofs are intact Given a detected linkage break (missing event, invalid signature, digest mismatch, or failed chain check) during runtime or export When detection occurs Then the system emits a proactive alert to monitoring and marks the affected quote as non-defensible until resolved
Signer Identity & Key Management
"As a security administrator, I want managed signer identities with key rotation so that signatures remain trustworthy and auditable over time."
Description

Provide robust identity and key management for all human and machine actors that sign ledger events, including per-tenant keys, role-based access, and automated key rotation. Integrate with SSO (SAML/OIDC) for human identities and a KMS/HSM for service keys, exposing a JWKS endpoint for verification. Support device-level attestation where available and record the binding between signatures and verified identities. Maintain auditable key lifecycle logs (creation, rotation, revocation) and enforce signing policies (algorithms, key sizes, expiration). Ensure backward verification of historical events after rotations by preserving public key versions and certificate chains.

Acceptance Criteria
SSO Identity Federation with Role Mapping for Signers
Given a tenant configured with SAML and/or OIDC SSO and role mappings When a human user authenticates via the IdP Then a signer identity is established with a stable subject (sub), issuer (iss), and mapped roles Given a signed-in human user with the "can_sign_ledger" role When the user initiates a ledger signing action Then the produced signature metadata includes subject, issuer, role snapshot, and authentication time (auth_time) When the IdP denies or omits the required role Then signing is prevented with HTTP 403 and an audit log entry containing user, issuer, and reason When the same user signs again after a role change at the IdP Then the new role snapshot is reflected on subsequent ledger events within 60 seconds of claim propagation
Per-Tenant Non-Exportable Keys in KMS/HSM
Given a new tenant is onboarded When the system provisions keys Then a unique tenant-scoped signing key is generated within the configured KMS/HSM as non-exportable And key metadata records algorithm, key size, created_at (UTC), key id (kid), and tenant id When any process attempts to export private key material Then the operation is rejected and audited When a request from Tenant A attempts to sign using Tenant B’s key Then the system returns 403 and no signature is produced
Automated Key Rotation with Backward Verification
Given a tenant policy that requires rotation every 90 days or upon compromise When a key reaches its rotation threshold or a manual rotation is triggered Then a new key version is created and set active for new signatures within 60 seconds And the previous public key and associated certificate chain remain published for verification for at least 180 days (configurable) When verifying historical ledger events signed before rotation Then verification succeeds using the preserved key version and certificate chain If rotation fails at any step Then signing is paused for that tenant, an alert is sent to operators, and the failure is logged with error details
JWKS Endpoint Compliance and Timely Propagation
Given the public JWKS endpoint is requested at /.well-known/jwks.json over HTTPS When the request is made Then the response is RFC 7517-compliant and contains all active and previous verification keys with kid, kty, alg, use=sig, and x5c/x5u when applicable And the response includes Cache-Control and ETag headers, and updates propagate within 60 seconds after key changes When an invalid HTTP method or unauthenticated access occurs Then the server returns an appropriate 4xx without leaking sensitive data When a JWS produced by the service is verified against the JWKS Then verification succeeds for both current and historical events Then the endpoint maintains 99.9% monthly availability with uptime metrics recorded
Device-Level Attestation Enrollment and Binding
Given a supported platform providing WebAuthn/TPM attestation When a user enrolls a device Then the attestation evidence is validated, bound to the user identity, and stored with AAGUID, attestation format, and certificate chain When a signing event is initiated from an enrolled device Then the event metadata includes a reference to the enrolled device, a nonce, and the attestation result When attestation is missing or fails validation and tenant policy requires attestation Then signing is blocked with 403 and the attempt is audited; otherwise the event is marked "unattested" When an attempt is made to reuse or spoof attestation artifacts Then the request is rejected and logged
Immutable Key Lifecycle Audit Logging and Export
Given any key lifecycle operation (create, rotate, revoke) When it occurs Then an append-only log entry is recorded with tenant id, actor (human/service), key id, key version, UTC timestamp, operation type, reason code, and hashes of public material And lifecycle logs are immutable (append-only), queryable by tenant and time range, and exportable to signed JSON and CSV with a checksum/Merkle root for tamper evidence When an auditor requests a report for a date range up to 10,000 records Then the system returns results within 10 seconds with verifiable integrity artifacts
Signing Policy Enforcement and Violations Handling
Given a tenant signing policy defining allowed algorithms, minimum key sizes, maximum key age, and attestation requirement When a signing attempt violates any rule Then the request is denied with 403 and a machine-readable error code and is fully audited When a signing attempt complies with policy Then the signature is produced with the configured alg and kid, and the event includes the policy version id and policy effective timestamp When a key’s maximum age is exceeded Then further signing with that key is blocked until rotation completes; historical verification remains unaffected When a policy is changed Then the change is versioned, audited, and takes effect for new signings within 60 seconds
Environment Provenance Capture
"As a platform engineer, I want standardized environment provenance captured so that outputs can be reproduced and explained during audits."
Description

Capture and normalize environment metadata for each event, including application build/version, OS and kernel version, device ID, region and timezone, IP at time of action, AI model/version and container image digest, hardware characteristics (CPU/GPU), and dependency manifests. Store this metadata as a verifiable, schema-versioned record referenced by event IDs to support reproducibility and context under audit. Implement privacy controls to avoid collecting unnecessary PII and provide tenant-level configuration for what is captured, redacted, or anonymized while maintaining evidentiary value.

Acceptance Criteria
Per-Event Provenance Metadata Coverage and Normalization
Given an event is emitted in ClipSpark, When provenance capture runs, Then the record includes non-empty values for appBuild, appVersion, osName, osVersion, kernelVersion, deviceId, region, timezone, ip, aiModelName, aiModelVersion, containerImageDigest, cpuModel, gpuModel (if present), and dependencyManifest. Given timestamps are recorded, When stored, Then they use ISO 8601 UTC (e.g., 2025-09-13T15:04:05Z) and the original timezone is captured in a separate field. Given heterogeneous platforms and hardware, When values are written, Then they conform to normalization rules defined in the active schemaVersion and pass schema validation. Given an eventId E, When querying provenance by eventId, Then exactly one provenance record exists for E and foreign-key integrity is enforced.
Schema Versioning, Validation, and Backward Compatibility
Given a provenance record is created, When persisted, Then it includes schemaVersion and recordHash fields and validates against the JSON Schema for that schemaVersion. Given schemaVersion is advanced to a new version, When creating new records, Then legacy records remain readable and validate against their original schemaVersion without migration. Given a record is missing required fields or contains disallowed fields, When validation runs, Then the write is rejected with a 4xx error code and an audit entry noting the validation failure. Given a recordHash is stored, When recomputing the hash over the canonicalized record, Then the value matches exactly.
Tenant Privacy Controls: Capture, Redact, and Anonymize
Given tenant privacy settings set a field (e.g., ip or deviceId) to do_not_capture, When provenance is captured, Then that field is omitted and a redactionReason is recorded. Given tenant privacy settings set a field to redact, When provenance is captured, Then that field is stored as null and a redactionReason is recorded. Given tenant privacy settings set a field to anonymize, When provenance is captured, Then that field is stored as an irreversible anonymized representation with anonymizationMethod metadata from the approved methods registry and the value differs from the original. Given default settings, When provenance is captured, Then no fields outside the approved metadata set are persisted (PII minimization check passes with zero violations). Given tenant privacy settings change, When the next event is captured, Then the new configuration is applied prospectively and is logged with configVersion in the record.
Verifiable and Immutable Provenance Record
Given a provenance record is created, When stored, Then it includes signature, signatureKeyId, and recordHash fields and the signature verifies against the published public key for signatureKeyId. Given a stored provenance record, When an update attempt is made, Then the system rejects the mutation (HTTP 409/Forbidden) and instructs to create a new record linked by previousRecordHash if a correction is needed. Given storage corruption or tampering occurs, When validation compares recordHash/signature to stored content, Then a mismatch is detected and an alertable error is logged with severity=high.
Provenance Retrieval for Audit by Event ID
Given a valid eventId E, When requesting provenance via the retrieval API, Then the service returns HTTP 200 with a single record that validates against its schemaVersion and includes privacyPolicyApplied, schemaVersion, recordHash, and (if present) signature fields. Given a nonexistent eventId, When requesting provenance via the retrieval API, Then the service returns HTTP 404 with no body fields containing sensitive data. Given a provenance record is returned, When signature verification is performed client-side, Then verification succeeds for untampered records and fails for altered content. Given retrieval requests are made, When auditing access logs, Then each request is logged with requester identity, timestamp, and outcome without exposing redacted/anonymized values in the logs.
AI Model, Container, and Dependency Manifest Provenance
Given an event runs an AI model in a container, When provenance is captured, Then the record includes aiModelName, aiModelVersion, containerImageDigest (e.g., sha256:...), and runtime framework versions. Given dependency scanning is enabled, When provenance is captured, Then dependencyManifest includes package name and version entries for the runtime environment and a manifestHash is stored. Given the container image used for the event is available, When the image digest is re-derived, Then it exactly matches the containerImageDigest stored in the record. Given GPU is not present, When provenance is captured, Then gpuModel is omitted and the record still validates against the schema.
Real-time Integrity Validation & Alerts
"As an operations manager, I want real-time alerts when custody linkage breaks so that we can quarantine and remediate issues before export."
Description

Continuously validate the chain of custody during processing by verifying hash links, signatures, timestamps, and expected state transitions. On detection of gaps, mismatches, out-of-order events, or signature failures, automatically quarantine affected artifacts, halt downstream processing per tenant policy, and issue proactive alerts via in-app notifications, email, and webhooks. Provide a dashboard that surfaces chain health, failure reasons, and remediation actions, with audit logs for all alerting and resolution activity.

Acceptance Criteria
Real-time Validation Across Processing States
Given a new custody event is persisted for an artifact When the validation service observes the event Then within 5 seconds it validates hash linkage, digital signature, timestamp monotonicity (no regress vs prior event), and presence of required environment metadata, and records the result And for 100% of event types (capture, ingest, transcode, chunk, caption, summarize, highlight, export) validation is executed And if all checks pass, the artifact chain_health remains "Healthy" and the cumulative hash/head pointer is advanced And if any check fails, the result includes failure reason codes and the event is marked invalid for downstream use
Cryptographic Hash-Link and Signature Verification
Given an event with previous_hash, payload, signature, and key_id When the system re-computes current_hash using SHA-256 over the canonicalized payload and compares previous_hash to the last committed head Then a mismatch yields failure reason code HASH_MISMATCH with expected vs actual values captured And the signature is verified against the tenant’s active public key for key_id using Ed25519 or ECDSA P-256, and canonicalization rules are applied deterministically And if the key is revoked or not found at event.timestamp, the validation fails with SIGNATURE_INVALID or KEY_REVOKED And the verification record stores hash algo, key_id, algo, and verification outcome for audit
Automatic Quarantine and Policy-based Processing Halt
Given a validation failure is detected for an artifact When tenant policy requires halt_on_failure Then the artifact is set to Quarantined within 2 seconds and new downstream jobs for that artifact are prevented from scheduling or execution And existing in-flight jobs for that artifact are cancelled or paused per policy within 3 seconds And exports for the artifact are blocked until the quarantine is cleared by an authorized user action And clearing quarantine requires Custody Admin role and triggers immediate revalidation of the chain
Proactive Multi-channel Alerts with Delivery Guarantees
Given a validation failure or quarantine change occurs When alerting is enabled for the tenant Then an in-app notification appears for scoped users within 2 seconds, an email is delivered within 60 seconds, and a webhook POST is attempted within 5 seconds And the alert payload contains artifact_id, tenant_id, event_id, processing_stage, severity, failure_reason_codes, detected_at (UTC), correlation_id, policy_applied, quarantine_state, and dashboard_url And duplicate alerts for the same artifact_id + reason_code are deduplicated within a 5-minute incident window And webhook requests include an HMAC-SHA256 signature header over the body, retry up to 6 times with exponential backoff (30s to 16m), and route to a dead-letter queue after exhaustion
Chain Health Dashboard Visibility and Remediation
Given a user with appropriate role opens the Chain Health dashboard When viewing a tenant and time window Then artifacts display statuses: Healthy, Warning, Failed, Quarantined, Pending, with real-time updates (<5 seconds) And the user can filter by status, processing_stage, reason_code, and search by artifact_id And selecting a Failed artifact shows a timeline with the offending event, expected vs actual hash, signature key_id, timestamp checks, and environment metadata snapshot And remediation actions are available per role: Retry Validation, Re-ingest Event, Acknowledge & Proceed (if policy allows), Dismiss with justification; each action updates state and triggers revalidation with results reflected within 5 seconds
Comprehensive Audit Logging and Signed Ledger Export
Given alert emissions, delivery attempts, quarantine/unquarantine, remediation actions, and policy changes occur When these actions are executed Then each is appended to an immutable audit log with fields: actor_id (or system), action, target_type, target_id, prior_state, new_state, reason, timestamp (UTC ISO8601), correlation_id, and outcome And audit entries are hash-chained and tamper-evident; writes are atomic and failures surface as errors while the triggering operation fails closed And the dashboard allows filter/search of audit entries by artifact_id, action, actor, and time range and supports export And on artifact export, a signed ledger file is produced containing the custody chain and related audit entries, with a detached signature verifiable against the tenant public key and a SHA-256 checksum
Signed Ledger Export & Verification
"As a legal reviewer, I want a signed ledger included with each export so that external parties can independently validate the chain of custody."
Description

Bundle a signed, minimal ledger excerpt with every exported exhibit (captions, summaries, highlights) containing the relevant event chain, content hashes, and environment references. Produce both human-readable (PDF/HTML) and machine-verifiable (JSONL) packages signed using standard formats (JWS/COSE) with a timestamp and certificate chain. Provide a public verification utility (CLI and web page) that validates signatures, hash continuity, and artifact checksums against the export, enabling third parties to independently confirm custody without accessing internal systems.

Acceptance Criteria
Bundle Signed Ledger With Every Exported Exhibit
Given a user exports an exhibit of type captions, summaries, or highlights When the export completes Then the bundle contains exactly one exhibit artifact, one human-readable ledger (PDF or HTML), and one machine-verifiable ledger (JSONL) And both ledger packages reference the exhibit by deterministic artifact ID and checksum And both ledger packages are signed using JWS or COSE And each signature embeds a signing timestamp and certificate chain
Minimal, Relevant Ledger Excerpt
Given an exported exhibit bundle When inspecting the JSONL ledger excerpt Then it contains only events that contribute to the exhibit’s lineage from capture through export And each event includes event_id, event_type, occurred_at (RFC 3339), env (name, version, os), content_hash, and prev_event_hash And the excerpt conforms to the published JSON Schema (version 1.0) And the first record’s prev_event_hash equals the capture anchor hash for the source And no unrelated session/event identifiers are present
JSONL Signature and Offline Verification
Given the JSONL ledger and its signature in the export bundle When the public CLI verifies the ledger on a machine without internet access Then verification succeeds using only files packaged in the bundle And the signature format is JWS (compact or JSON) or COSE_Sign1 And the certificate chain in the signature is present and validates to a trusted root provided in the bundle And the signing timestamp is present, not more than 5 minutes in the future, and the certificate was valid at signing time
Human-Readable Package Fidelity
Given the human-readable PDF/HTML ledger in the bundle When a user opens it Then it displays signer identity, signing timestamp, certificate chain summary, exhibit artifact ID and checksum, and an ordered event timeline with environment metadata And all displayed hashes and IDs exactly match those in the JSONL ledger And it includes clear, step-by-step instructions for verifying the bundle via CLI and web without accessing internal systems
Hash Continuity and Artifact Checksum Validation
Given an unmodified export bundle and exhibit artifact When the CLI verification runs against the bundle Then it reports PASS with exit code 0 And for every event i>0, hash(event[i-1]) equals prev_event_hash(event[i]) And checksum(exhibit artifact) equals the recorded artifact checksum in the ledger When any ledger line or the artifact file is altered Then it reports FAIL with exit code 1 and identifies the failing check
Public Web Verification Page (Client-Side)
Given the public verification web page When a user drags and drops the export bundle Then all checks (signature, certificate chain, timestamp, hash continuity, artifact checksum, JSONL schema) run entirely client-side without uploading data And the page supports current Chrome, Firefox, and Safari versions And it displays a clear pass/fail result and a detailed checklist of validations And it allows downloading a JSON verification report equivalent to the CLI --report output
Quote-to-Artifact Traceability
"As a content creator, I want each caption and highlight mapped to its source with proof so that I can confidently share verifiable moments."
Description

Ensure every caption line, summary bullet, and highlight clip can be traced back to the exact source time range and corresponding ledger event IDs. Embed trace IDs and content digests into generated artifacts and expose them via API and UI, enabling one-click navigation from any output to its source with verification status. Enforce propagation of provenance through transforms (e.g., diarization, summarization) so derived artifacts reference all contributing source events, providing granular, context-rich proof of origin.

Acceptance Criteria
UI One-Click Source Navigation from Caption Line
Given a caption line is displayed in the ClipSpark transcript panel with an attached traceId and sourceTimeRange When the user activates "Go to Source" on that line Then the video player seeks to the exact startTime within ±50ms and highlights the full sourceTimeRange duration And the UI reveals the associated ledgerEventIds for that line And the verificationStatus indicator shows "Verified" if the line's contentDigest matches the ledger, else "Failed" And the seek-and-highlight completes within 500 ms on median across 50 interactions
API Trace Metadata for Summary Bullet
Given a summary bullet artifact exists with id {artifactId} When a client calls GET /v1/artifacts/{artifactId} Then the response status is 200 and Content-Type is application/json And the payload includes fields: traceIds (array, length >= 1), sourceTimeRanges (array of {start,end}), ledgerEventIds (array, length >= 1), contentDigest (SHA-256 hex), verificationStatus (enum: Verified|Failed|Pending) And contentDigest matches regex ^[a-f0-9]{64}$ and equals the SHA-256 of the normalized artifact content And each ledgerEventId resolves via GET /v1/ledger/{id} with 200
Highlight Clip Provenance Across Multiple Segments
Given a highlight clip is generated from N (N >= 2) non-contiguous source segments When the clip artifact metadata is created Then metadata includes exactly N sourceTimeRanges and their corresponding ledgerEventIds without loss or duplication And the UI displays a segment list of length N And clicking a segment i navigates the player to the correct time range i within ±50ms And segment navigation latency is <= 500 ms p50 and <= 1000 ms p95 over 100 interactions
Export Embeds Trace IDs, Digests, and Signed Ledger
Given a user exports captions (SRT/VTT), a summary (JSON/Markdown), or a highlight clip (MP4) When the export completes Then each file embeds trace metadata: traceIds, ledgerEventIds, and contentDigest in a documented, parseable location (SRT/VTT comment lines; JSON fields; MP4 metadata) And an adjacent ledger file (ledger.json and ledger.sig) is written containing all referenced ledger events And verifying ledger.sig with the platform public key succeeds (ed25519 or RSA per spec) And recomputing each exported file's contentDigest matches the ledger record
Verification Status and Alert on Broken Linkage
Given a ledger lookup fails or a contentDigest mismatch is detected for any artifact When the artifact is viewed in the UI or fetched via API Then verificationStatus is "Failed" And the UI shows an alert banner and audit-log entry with errorCode and firstDetectedAt timestamp And the API response includes verificationStatus=Failed and error details with HTTP 409 And exports of failed artifacts are blocked or include a prominent "Unverified" flag in embedded metadata
Provenance Preservation Through Transforms
Given diarization and summarization transforms produce derived artifacts from source captions/audio When derived artifacts are created Then each derived artifact records references to all contributing source ledgerEventIds and sourceTimeRanges And the lineage endpoint GET /v1/lineage/{artifactId} returns a DAG containing edges to each contributing source event (edge count >= number of contributing events) And a random sample of 100 derived artifacts shows 100% include at least one source reference and 0% include orphan references
Tamper-Evident Storage & Retention Controls
"As a records manager, I want tamper-evident storage with retention and legal holds so that we meet regulatory requirements without compromising audit trails."
Description

Store ledger records and referenced artifacts in immutable, append-only storage with object lock/WORM capabilities and server-side encryption. Support configurable retention schedules, legal holds, and export of deletion tombstones that preserve audit continuity while meeting privacy obligations (e.g., selective redaction with traceable redaction events). Expose administrative controls and reports demonstrating retention policy compliance and the integrity of stored records over time.

Acceptance Criteria
Write-Once Immutable Ledger Storage with Object Lock
- Given WORM storage is configured with object lock in compliance mode for ledger and artifact buckets, When a new ledger entry and its referenced artifact are written, Then both objects are stored append-only with objectLockMode=COMPLIANCE and retentionUntilDate set per active policy. - Given a locked ledger entry or artifact exists before retention expiry, When any client attempts modify/overwrite/delete via API or console, Then the operation is rejected with 403 and an audit event is recorded with actor, timestamp, target, and reason="Immutable/UnderRetention". - Given two consecutive ledger entries exist, When integrity verification is run, Then the later entry includes the previous_entry_hash and verification returns chain_intact=true. - Given a ledger object is retrieved, When headers/metadata are inspected, Then object lock mode, retentionUntilDate, checksum, and encryption metadata are present and non-null.
Configurable Retention Policies Applied and Enforced
- Given an admin creates a retention policy with name, scope, and duration (e.g., 7 years) and applies it to a workspace, When new ledger entries and artifacts are created in that scope, Then retentionUntilDate = finalized_timestamp + policy_duration and is stored immutably. - Given an admin updates a retention policy, When existing records are evaluated, Then their retentionUntilDate is not decreased (only equal or increased) and the change is audited with before/after values. - Given a record reaches retention expiry and is not on legal hold, When the retention job runs, Then the record is deleted and a deletion tombstone is created and linked in the ledger. - Given a user attempts manual deletion prior to expiry without legal basis, When the deletion request is made, Then the system denies the action with 403 and logs policy_id, record_id, and reason="RetentionActive".
Placing and Releasing Legal Holds
- Given an authorized compliance officer submits a legal hold with case_id and justification for selected records (by id/range/query), When the hold is applied, Then deletion is prevented regardless of retention expiry and a legal_hold_applied event is recorded. - Given a record under legal hold reaches retention expiry, When the retention job runs, Then the record is not deleted and is reported as "Expired—On Hold". - Given a legal hold release is requested, When two distinct approvers approve within the configured window, Then the hold is removed, both approvers are logged, and the record becomes eligible for deletion at the next retention cycle. - Given an unauthorized user attempts to place or release a legal hold, When the request is made, Then the action is denied with 403 and the attempt is audited.
Exporting Deletion Tombstones and Redaction Manifests
- Given a record is deleted after retention expiry and is not on legal hold, When deletion occurs, Then a tombstone is appended with record_id, previous_hash, content_hash_at_deletion, deletion_timestamp (UTC ISO 8601), policy_id, actor=system, and a signature; the ledger chain remains verifiable. - Given a compliance auditor requests an export for a date range, When the export is generated, Then it includes all tombstones and redaction events in JSON and CSV plus a signed manifest with a SHA-256 checksum of the export files. - Given selective redaction is performed to satisfy a privacy request, When the redaction executes, Then a redaction event is recorded with who, when, reason_code, scope (byte/time ranges), and post_redaction_hash, and the event is linked into the ledger. - Given a tombstone or redaction event is tampered with, When chain verification is run, Then verification fails and identifies the exact position of breakage.
Server-Side Encryption and Key Management
- Given encryption at rest is enabled with a KMS-managed key, When a ledger entry or artifact is stored, Then the object is encrypted (AES-256 or stronger) and metadata indicates algorithm and key_id; key usage is present in access logs. - Given a KMS key is rotated, When subsequent objects are stored, Then new objects use the new key version; existing objects remain decryptable; the rotation event is recorded in the audit trail. - Given an attempt is made to store an object without required encryption, When the write is attempted, Then the operation is rejected and an alert is issued to administrators. - Given an auditor tests encryption compliance, When N randomly selected objects are queried via API, Then 100% include encryption metadata present=true.
Automated Integrity Verification and Alerting
- Given daily integrity verification is scheduled, When it runs, Then it verifies hash chains, object lock status, and required metadata for all records and writes a results summary with pass/fail counts and error details. - Given any verification check fails (e.g., chain break, missing object lock, absent encryption metadata), When the failure is detected, Then alerts are sent via email and webhook within 15 minutes containing tenant_id, record_id, check_type, and correlation_id. - Given the alert webhook endpoint is unreachable, When delivery is attempted, Then the system retries with exponential backoff for at least 24 hours and logs all attempts. - Given an alert is received, When the referenced record is queried, Then a corresponding audit event exists linking the failure to the record and verification run id.
Administrative Compliance Reporting
- Given an admin requests a retention compliance report for a scope and period, When the report is generated, Then it includes counts by policy, upcoming expirations, deletions executed, holds applied/released, exceptions, and integrity verification results, and is exportable as CSV and PDF. - Given a report is exported, When the export completes, Then a detached signature file (.sig) and SHA-256 checksum are produced to verify report integrity. - Given filters (policy_id, date range, record type) are applied, When the report query runs, Then results honor filters and complete within 60 seconds for up to 1,000,000 records. - Given scheduled reporting is configured, When the schedule triggers, Then the latest report is generated and delivered to configured destinations (email/webhook/storage) with delivery status logged.

Outcome Mapper

Automatically aligns AI-generated chapters to clear, measurable learning objectives using Bloom’s taxonomy. Suggests stronger action verbs, highlights gaps or overlaps, and builds an objective-to-timestamp traceability matrix—so courses are instructionally sound and accreditation-ready with far less manual rework.

Requirements

Objective Authoring & Import
"As an instructional designer, I want to author and import learning objectives for a video so that Outcome Mapper can align content to measurable outcomes."
Description

Provide a workspace to create, edit, and manage course learning objectives for each ClipSpark project. Support bulk import via CSV/TSV, copy-paste, and API, with automatic parsing of action verbs, detection of Bloom’s taxonomy level, normalization, and deduplication. Validate objectives against measurability and clarity rules, flag ambiguous terms, and suggest fixes. Persist version history, tags, and ownership, and associate objectives to videos, playlists, and cohorts. Expose an SDK endpoint for programmatic objective management and sync updates across the Outcome Mapper pipeline.

Acceptance Criteria
Objective Workspace CRUD with Inline Validation
Given a project with no objectives, when a user creates a new objective providing required fields (text ≤ 500 chars, owner), then the objective is saved with a unique ID and appears in the list within 1 second. Given an existing objective, when the user edits the text and saves, then the change is persisted and visible after page reload and API refetch. Given the create/edit form, when required fields are missing or exceed limits, then the Save action is disabled and inline error messages identify each offending field. Given the objective list, when the user filters by tag or owner, then only matching objectives are shown and the total count reflects the filter.
Bulk Import via CSV/TSV and Copy-Paste with Parsing and Deduplication
Given a valid CSV/TSV file with headers [Objective, Owner, Tags] and 1,000 rows, when uploaded, then at least 99% of valid rows import within 30 seconds and a summary shows counts for imported, skipped (duplicates), and errors. Given duplicate objectives differing only by case/whitespace/punctuation, when imported, then duplicates are not created and are reported as "Skipped — Duplicate". Given multi-line copy-paste input (one objective per line), when processed, then each non-blank line becomes a new objective; blank lines are ignored; trailing/leading spaces are trimmed. Given a file missing the Objective column or containing malformed rows, when imported, then the import fails atomically with a per-row error report and no objectives are created. Given imported objectives, when parsing completes, then action verbs are extracted and stored, and objective text is normalized (trimmed, collapsed whitespace, standardized punctuation).
Automatic Bloom Level Detection and Verb Recommendations
Given a curated test set of 50 objectives with gold-standard Bloom levels, when processed, then the assigned Bloom level matches the gold standard for ≥ 90% of objectives. Given an objective that uses weak or ambiguous verbs, when analyzed, then the system recommends at least 3 stronger, level-appropriate action verbs. Given an objective with no identifiable action verb, when analyzed, then the system flags "Missing Action Verb" and does not assign a Bloom level until corrected.
Measurability and Clarity Validation with Fix Suggestions
Given an objective containing ambiguous terms (e.g., "understand", "learn about"), when validated, then it is flagged with category AmbiguousVerb and replacement suggestions are provided. Given an objective missing measurable elements (condition, behavior, or degree), when validated, then the missing element(s) are identified and a template suggestion is offered: "Given [condition], learner will [behavior] to [degree]". Given an objective with unbounded scope or undefined subject, when validated, then the system flags UnboundedScope or UndefinedSubject and provides example fixes. Given a user accepts a suggested fix, when applied, then the objective text updates and a new version is recorded.
Version History, Tags, and Ownership Persistence
Given an objective with multiple edits by different users, when viewing version history, then each version shows timestamp, editor, and diff of changes; restoring a prior version creates a new version entry with restored content. Given an objective with tags and owner set, when the project is reloaded or fetched via API, then the tags and owner persist unchanged. Given a search by tag or owner, when executed, then results include all and only objectives matching the criteria.
Associations to Videos, Playlists, and Cohorts
Given an objective, when it is associated to a video, a playlist, and a cohort, then the associations are saved and the objective appears in each entity’s objective list. Given an existing association, when it is removed and saved, then the association no longer appears and the objective remains intact. Given an objective associated to multiple entities, when fetched via UI or API, then all associated entity IDs and types are returned/displayed accurately.
SDK Endpoint for Objective Management and Pipeline Sync
Given valid API credentials, when calling POST /objectives with {projectId, text, owner, tags}, then the API returns 201 with objectiveId, and validation/Bloom processing is enqueued. Given an existing objective, when calling PUT /objectives/{id} to update text/tags/owner, then the API returns 200, a new version entry is created, and Outcome Mapper pipeline reflects the update within 2 minutes. Given an invalid payload or missing permissions, when calling any SDK method, then the API returns a 4xx with machine-readable error codes and no partial writes occur. Given a webhook subscription for objective.updated, when an objective changes via UI or API, then a webhook is delivered within 2 minutes including eventId, objectiveId, and a change summary.
Automated Chapter-to-Objective Alignment
"As an educator, I want chapters automatically mapped to my learning objectives so that I can quickly see where each outcome is addressed."
Description

Automatically align AI-generated chapters and sub-segments to defined learning objectives using NLP over transcripts, captions, and metadata. Produce many-to-many mappings with confidence scores, evidence snippets, and timestamp ranges; refresh alignments when chapters or objectives change. Support multilingual transcripts and domain-specific vocabularies, and allow configuration of sensitivity thresholds. Surface the alignment inline within the ClipSpark chapter view for immediate context.

Acceptance Criteria
Many-to-Many Alignment with Confidence, Evidence, and Timestamps
Given a project with AI-generated chapters and defined learning objectives When the alignment process runs Then each chapter–objective pair includes a confidence score between 0.00 and 1.00, at least one verbatim evidence snippet, and one or more timestamp ranges with start and end times And chapters may align to multiple objectives and objectives may align to multiple chapters And no duplicate chapter–objective pairs are emitted And alignments are sorted by descending confidence within each chapter
Threshold Configuration Filters Alignments
Given the alignment sensitivity threshold is set to T for the project When viewing alignments in the chapter view Then only alignments with confidence >= T are displayed And changing T updates the visible alignments in-place without page reload And the selected T persists for the project across sessions
Domain Vocabulary Boost and Refresh
Given a domain-specific vocabulary with terms and synonyms is uploaded and enabled When the alignment process runs Then evidence snippets highlight matched domain terms and synonyms And at least one affected chapter–objective pair receives a strictly higher confidence score than the same run without the vocabulary And updating or disabling the vocabulary triggers automatic re-alignment and the UI reflects the change
Multilingual Transcript Support
Given a transcript language set to English, Spanish, or French with objectives provided in the same language When the alignment process runs Then valid alignments are produced with evidence and timestamps for that language’s segments And language-specific tokenization handles inflected forms of objective verbs And diacritics are handled so matches are not missed due to accent marks
Inline Alignment in Chapter View with Deep Links
Given a user opens the ClipSpark chapter view for a processed video When viewing a chapter row Then the aligned objectives are listed inline with their confidence scores, evidence snippets, and timestamp ranges And clicking a timestamp seeks the player to the start time of that range And clicking an objective opens the objective’s details in context
Change-Driven Realignment on Chapter or Objective Edits
Given chapters are edited (split, merge, add, delete, rename) or objectives are added, deleted, or edited When changes are saved Then alignments are recomputed using the latest chapters and objectives And alignments to deleted chapters or objectives are removed And the chapter view reflects the new mappings without showing stale results
Evidence Source Attribution Across Transcripts, Captions, and Metadata
Given transcripts, captions, and video metadata are available for a project When the alignment process runs Then evidence snippets indicate their source type (transcript, caption, or metadata) And a chapter–objective pair may include multiple evidence snippets from different sources And disabling a source in project settings excludes it from evidence and subsequent alignments
Verb Strengthener & Bloom Validator
"As a course author, I want suggestions for stronger action verbs and Bloom levels so that my objectives are clear and accreditable."
Description

Analyze each objective’s verb and structure to classify its Bloom level and recommend stronger, measurable action verbs and rewrites. Provide inline suggestions with side-by-side diffs, explanations for why the change improves specificity, and one-click apply/rollback. Enforce organization-specific verb lists and style guides, and recalculate Bloom level upon acceptance. Log all changes to maintain accreditation-friendly traceability.

Acceptance Criteria
Inline Verb Suggestions with Side-by-Side Diff
Given an objective is loaded, When the analyzer runs, Then the system identifies the main action verb(s) and surfaces 1–3 stronger measurable verb suggestions aligned to the target Bloom level. Given suggestions exist, When the user opens the diff view, Then show a side-by-side original vs. proposed objective with changes highlighted and no unrelated text altered. Given multiple suggestions, When the user cycles through them, Then the diff updates within 200 ms and maintains cursor/selection state. Given no stronger verb is appropriate, When analysis completes, Then display a clear “No stronger verb suggested” state with reason code.
Bloom Level Classification and Recalculation on Acceptance
Given an objective, When analyzed, Then classify its Bloom level (Remember/Understand/Apply/Analyze/Evaluate/Create) and display a confidence score between 0.00 and 1.00. Given an objective contains multiple verbs, When classified, Then select the highest Bloom level present and display the contributing verb(s). Given a user accepts a rewrite, When Apply is clicked, Then recalculate the Bloom level and update the badge within 500 ms while storing old/new levels for audit. Given a user rolls back a change, When Rollback is clicked, Then restore the prior text and Bloom level and clear the pending state.
Organization-Specific Verb List Enforcement
Given an organization has an allowed verbs list by Bloom level, When an objective uses a verb not on the allowed list for its target level, Then flag noncompliance and suggest at least 2 allowed alternatives. Given a blocked verbs list exists, When a user attempts to apply a rewrite containing a blocked verb, Then prevent save and display the blocking rule ID and guidance. Given no org-specific lists are configured, When analysis runs, Then default to the system verb library and note the default source in the UI.
One-Click Apply and Rollback of Objective Rewrites
Given suggestions are visible, When the user clicks Apply, Then replace the objective inline without page reload, increment the objective version, and mark the change as Draft-Applied. Given a change is applied, When the user clicks Rollback within 30 days, Then revert to the previous version, restore prior Bloom classification, and mark the rollback in history. Given the objective is mapped to chapters/timestamps, When Apply executes, Then the traceability matrix remains valid (0 broken references) as confirmed by an integrity check.
Explanations for Suggested Changes
Given a suggestion is presented, When the user clicks Why, Then display a 1–3 sentence explanation referencing Bloom taxonomy and measurability, with reading grade level ≤ 10 (FKGL or equivalent). Given the original objective is already measurable at the target Bloom level, When explanations are generated, Then explicitly state that and provide optional refinement rationale. Given style and verb rules contribute to the suggestion, When the explanation is shown, Then list the specific rules triggered (IDs/names) and how the suggestion resolves them.
Traceability Logging for Accreditation
Given any action (apply, rollback, override, rule enforcement), When it completes, Then append an immutable audit record with timestamp, user ID, objective ID, old/new text, old/new Bloom level, rule IDs, and a diff link. Given an audit query by objective ID and date range, When requested, Then return matching entries within 200 ms for up to 100 records. Given a compliance export is requested, When generated, Then produce CSV and JSON files with a cryptographic checksum (SHA-256) and record counts that match the query.
Style Guide Compliance Validation
Given a style guide (e.g., sentence case, length ≤ 160 chars, avoid passive voice), When an objective is analyzed, Then evaluate each rule and display pass/fail with rule IDs. Given a mandatory rule fails, When the user attempts to Apply a rewrite, Then block the action and show the failing rules and remediation tips. Given style rules are updated, When existing objectives are reanalyzed, Then recalculate compliance and flag objectives requiring review.
Gap & Overlap Analyzer
"As a program coordinator, I want to see gaps and overlaps between objectives and content so that I can fix coverage issues before publishing."
Description

Detect objectives with insufficient or zero aligned content (gaps) and chapters that map to an excessive number of objectives (overlaps). Present coverage heatmaps, thresholds, and actionable recommendations such as adding reinforcement, splitting objectives, or re-cutting chapters. Enable filtering by Bloom level, objective tags, and confidence score, and recalc metrics in real time as mappings or objectives update.

Acceptance Criteria
Gap Detection for Uncovered and Undercovered Objectives
Given a course with learning objectives, chapters, and AI-generated objective-to-timestamp mappings And a gap coverage threshold of 0.25 is configured at the course level When the analyzer runs on the course Then any objective with total aligned duration ratio < 0.25 is flagged as a Gap (Undercovered) And any objective with zero aligned segments is flagged as a Gap (Uncovered) And each flagged objective displays objective ID, title, Bloom level, tags, coverage ratio (0–1), total aligned duration (mm:ss), and count of aligned segments And the heatmap shows gap cells in red for ratio < 0.25 and gray for 0 And a summary counter displays Gaps = X of N objectives (Y%)
Overlap Detection for Overloaded Chapters
Given a course with chapters and AI-generated mappings from chapters to multiple objectives And an overlap threshold of 5 objectives per chapter is configured When the analyzer runs on the course Then any chapter mapped to > 5 objectives is flagged as an Overlap And each flagged chapter lists the objective IDs, titles, and Bloom levels it maps to, plus the count of mapped objectives And the heatmap annotates overloaded chapter columns with an Overlap badge and highlights cells contributing to the overload And a summary counter displays Overlaps = C of M chapters (P%)
Coverage Heatmap Rendering and Interactions
Given a course with at least 10 objectives and 10 chapters and completed mapping data When the analyzer view is opened Then a coverage heatmap renders a matrix of objectives (rows) by chapters (columns) within 2 seconds for up to 2,500 cells And cell color scale is: gray=0 coverage, red=<threshold, yellow=≥threshold and <0.75, green=≥0.75 And hovering a cell shows a tooltip with objective ID/title, chapter title, aligned duration (mm:ss), coverage ratio, and confidence summary (min/median/max) And clicking a cell opens a side panel listing aligned timestamp segments with start–end times and confidence per segment
Multi-Facet Filtering by Bloom, Tags, and Confidence
Given Bloom level, objective tag, and minimum confidence filters are available And the minimum confidence filter is set to 0.80 And Bloom levels Remember and Understand are selected And tags include “assessment” and “intro” When the filters are applied Then the heatmap and all summary metrics recompute using only mappings with confidence ≥ 0.80 and only objectives matching the selected Bloom levels and tags And objectives or chapters with no remaining qualifying mappings after filtering are treated as zero coverage for computation and visualization And gap and overlap flags update immediately to reflect the filtered state
Real-Time Recalculation on Mapping or Objective Updates
Given the analyzer view is open with current metrics and heatmap rendered When a user adds, edits, or deletes a mapping segment or updates an objective’s metadata (Bloom level, tags) or deletes an objective Then all affected coverage ratios, gap flags, overlap flags, and heatmap cells update within 500 ms of the change being saved And summary counters and thresholds indicators refresh without a manual reload And an inline toast confirms recalculation completed successfully
Actionable Recommendations for Gaps and Overlaps
Given gaps and overlaps have been identified by the analyzer When the user opens the Recommendations panel Then each gap objective includes at least one actionable recommendation such as “Add reinforcement segment,” with a rationale referencing the current coverage ratio and threshold And each overlap chapter includes at least one actionable recommendation such as “Split chapter” or “Re-cut to isolate objectives,” with a rationale referencing the mapped objective count and threshold And each recommendation includes estimated impact on gap/overlap status and provides a one-click action to create a task or open the editor at suggested timestamps And accepting or dismissing a recommendation updates its status and is logged with timestamp and user ID
Threshold Configuration, Persistence, and Audit
Given configurable thresholds exist for gap coverage (ratio) and overlap count When an editor sets gap threshold to 0.30 and overlap threshold to 4 and saves Then the new thresholds validate (0 ≤ ratio ≤ 1, integer ≥ 1) and persist at the course level And the analyzer immediately recalculates flags and metrics using the new thresholds And the current thresholds are displayed in the UI near the heatmap legend And an audit entry records old value, new value, user ID, and timestamp
Traceability Matrix Export
"As an accreditation reviewer, I want a traceability matrix with timestamps and evidence so that I can verify objective coverage efficiently."
Description

Generate an objective-to-timestamp traceability matrix that includes objective IDs and text, Bloom level, mapped chapters/sub-segments, timecodes, confidence scores, and evidence quotes from the transcript. Offer exports to CSV, XLSX, and branded PDF, plus a secure shareable link and API endpoint. Preserve stable identifiers for round-trip integrity with external systems and include schema metadata for compliance audits.

Acceptance Criteria
CSV Export: Complete Fields and Formatting
Given a project with at least 5 learning objectives mapped to chapters and sub-segments When the user selects "Export CSV" for the traceability matrix Then a CSV file downloads within 10 seconds for up to 10,000 mappings And the file is UTF-8 encoded with BOM And the header columns appear in this exact order: objective_id,objective_text,bloom_level,chapter_id,chapter_title,subsegment_id,start_timecode,end_timecode,confidence_score,evidence_quote,source_video_id,source_video_title,model_version,schema_version,generated_at And start_timecode and end_timecode are zero-padded in HH:MM:SS.mmm format And confidence_score is a decimal between 0.00 and 1.00 with two decimal places And bloom_level is one of {Remember, Understand, Apply, Analyze, Evaluate, Create} And evidence_quote is enclosed in quotes and internal quotes are properly escaped And line endings are CRLF and there are no empty trailing rows And at least 99.9% of rows have non-empty objective_id, chapter_id, start_timecode, end_timecode
XLSX Export: Typed Columns and Large Dataset Handling
Given a project with 50,000 objective-to-timestamp mappings When the user selects "Export XLSX" Then an .xlsx workbook is generated within 15 seconds And the workbook contains a sheet named "Traceability" with a frozen header row And each column is typed as: objective_id (text), objective_text (text), bloom_level (text with data validation list of Bloom levels), chapter_id (text), chapter_title (text), subsegment_id (text, blank allowed), start_timecode (text), end_timecode (text), confidence_score (number with two decimals), evidence_quote (text), source_video_id (text), source_video_title (text), model_version (text), schema_version (text), generated_at (ISO-8601 text) And a second sheet named "Metadata" includes schema_version, model_version, generated_at (UTC ISO-8601), exporter_version, project_id, and field dictionary And no cell begins with '=', '+', '-', or '@' to prevent formula injection And the file size does not exceed 50 MB for 50,000 rows And Excel opens the file without repair prompts
Branded PDF Export: Layout, Branding, and Accessibility
Given an organization brand profile with logo (PNG/SVG), primary color, and footer text When the user selects "Export PDF" and chooses Letter size Then a PDF is generated within 30 seconds And each page header shows the organization logo and product name And each page footer shows page X of Y and the configured footer text And the PDF contains a section per objective with objective_id, objective_text, bloom_level, followed by a tabular list of mapped chapters with timecodes, confidence scores, and evidence quotes And evidence quotes longer than 300 characters are truncated with an ellipsis And timecodes are clickable deep links to the video at the specified start_timecode And the PDF includes a final appendix page with schema_version, model_version, generated_at, and export_id And the PDF text is selectable and searchable and includes bookmarks by objective
Secure Shareable Link: Immutable Snapshot with Access Controls
Given a user with permission to share exports When the user generates a shareable link Then a unique unguessable tokenized URL is created with a default expiration of 7 days and configurable range 1–90 days And the link points to an immutable snapshot of the matrix with fixed export_id and schema_version And accessing the URL without the token returns 403 And the owner can revoke the link, after which subsequent access returns 410 And an access log records timestamp, IP, user-agent, and export_id for each view And the snapshot content matches the original export byte-for-byte
API Endpoint: Retrieve Matrix with Versioned Schema
Given a valid API key scoped to the target project When a client calls GET /v1/traceability-matrix?project_id={id}&limit=100 with Accept: application/json Then the response status is 200 within 800 ms for 100 items And the response includes schema_version, model_version, generated_at (UTC ISO-8601), export_id, and an items array And items include objective_id, objective_text, bloom_level, chapter_id, chapter_title, subsegment_id, start_timecode, end_timecode, confidence_score, evidence_quote, source_video_id, source_video_title And results are ordered by objective_id then start_timecode ascending And pagination is provided via next_cursor when more items are available And unauthorized requests return 401 and cross-project access returns 403 And the OpenAPI spec documents fields, types, and error codes
Stable Identifiers: Round-Trip Integrity with External Systems
Given an external LMS stores ClipSpark objective_id, chapter_id, and subsegment_id from a prior export When the LMS requests the matrix via API filtering by those identifiers Then returned items include identical identifiers and align one-to-one with the LMS records And unchanged mappings retain the same identifiers across exports And removed mappings are absent and flagged in a diff endpoint with status=removed And updated mappings retain identifiers while reflecting new fields (e.g., confidence_score) And no duplicate identifiers are introduced in a single export And a content_hash per item allows the LMS to detect changes without field-by-field comparison
Compliance Metadata: Schema and Audit Readiness
Given any export format (CSV, XLSX, PDF) or API response When the export is generated Then a metadata block includes schema_version (semver), model_version, exporter_version, generated_at (UTC ISO-8601), project_id, source_video_ids, field_dictionary_url, and export_id And a SHA-256 checksum of the primary payload is provided and verified on download And the export validates against the published JSON Schema for the declared schema_version And an audit trail entry records who generated the export, at what time, and which source videos were included And a warning is surfaced if client requests a deprecated schema_version
Review Workflow & Manual Overrides
"As a team lead, I want to review and adjust mappings and objective text with an audit trail so that our course meets standards with accountability."
Description

Provide role-based review workflows to approve, comment on, and assign objective text, Bloom levels, and alignment mappings. Allow manual creation, adjustment, or removal of mappings via drag-and-drop across chapters and time ranges, with undo/redo and conflict resolution. Record an audit trail of who changed what and when, support draft vs. published states, and notify stakeholders of required actions.

Acceptance Criteria
Role-Based Approval and Commenting
Given a course with pending objectives When a user with Reviewer role opens Outcome Mapper Then they can add, edit, and resolve comments on objective text and mappings but cannot change state or publish Given a user with Editor role When they edit objective text or select a Bloom level from the allowed taxonomy list Then required fields are validated (objective text non-empty, one Bloom level selected) and invalid saves are blocked with inline error messages Given a user with Approver role When they approve or request changes on an objective Then the objective status updates accordingly, a timestamp and approver identity are recorded, and notifications are sent to the assignee and watchers Given task assignment is enabled When an editor assigns a reviewer/approver and due date to an objective Then the assignee and due date appear on the objective and are included in notifications
Manual Mapping via Drag-and-Drop
Given an objective and a chapter timeline with timestamps When a user drags the objective onto a chapter/time range and releases Then a mapping is created with start/end timestamps snapping to the nearest 1 second, a visible mapping chip appears, and the mapping is listed under the objective Given an existing mapping When the user drags the mapping chip or adjusts start/end handles Then the timestamps update accordingly, constrained within video bounds, and the UI reflects the new range within 150 ms Given overlapping mappings would result from a drop When the user releases the drag Then a conflict dialog offers Split, Replace, or Keep Both (with distinct labels), and the selected option is applied Given accessibility requirements When a user cannot use a mouse Then the user can focus a mapping and use keyboard controls (Left/Right = 1s nudge, Shift+Arrow = 5s) to adjust times and Enter to confirm
Undo/Redo History
Given a sequence of mapping and objective edits (create, delete, move, edit text, change Bloom level) When the user invokes Undo (Ctrl/Cmd+Z or toolbar) repeatedly Then each atomic change is reverted in reverse order up to at least 50 actions per user per course Given undone actions exist When the user invokes Redo (Ctrl/Cmd+Y or Shift+Ctrl/Cmd+Z) Then the reverted actions are reinstated in order unless a new change breaks the redo chain Given a Publish event has occurred When the course is in Published state Then Undo/Redo are disabled for that version and only available within an active Draft
Conflict Detection and Concurrent Editing
Given two users edit the same objective or mapping within 5 seconds of each other When the second user attempts to save Then the system detects a version conflict and presents options to Overwrite, Merge (field-level where possible), or Cancel, with Overwrite disabled by default Given users are viewing the same objective When one user enters edit mode Then the other sees real-time presence and a soft-lock indicator; the lock releases after 2 minutes of inactivity Given any conflict is resolved When the save succeeds Then the resolution choice, before/after values, and both user IDs are recorded in the audit log
Audit Trail and Traceability Matrix
Given any change to objective text, Bloom level, mapping ranges, approvals, comments, assignments, or state When the change is saved Then an immutable audit entry records user ID, role, timestamp (UTC), entity ID, field(s) changed, previous value(s), new value(s), and optional reason Given an auditor filters the history When filters for user, date range, entity type, action type are applied Then results update within 1 second and can be exported to CSV with the same filters Given the traceability matrix view is opened When objectives and mappings are loaded Then each objective lists its mapped chapters/timestamps and latest approval status, and the totals match the count of existing mappings without discrepancy
Draft vs. Published Workflow and Versioning
Given a course in Draft state When a user with Approver role clicks Publish Then preflight checks verify: 0 unresolved blocking comments, required approval policy satisfied (≥1 approver), no objectives missing Bloom level, and no unmapped objectives unless marked N/A with justification; failures block publish with a checklist of issues Given publish succeeds When the version snapshot is created Then the version receives a unique ID, becomes read-only, and is visible to viewers while edits occur only in a new Draft Given a prior Published version exists When a user with appropriate permissions selects Restore Then the system creates a new Draft cloned from that version without altering the original audit history
Notifications and Reminders
Given a reviewer or approver is assigned to an objective When the assignment is saved Then an in-app notification is delivered immediately and an email is sent within 1 minute containing course name, objective ID, due date, and a deep link Given an assigned task is overdue by 24 hours When reminders are processed daily Then the assignee receives up to 3 daily reminders, and on day 4 an escalation notification is sent to the project owner Given a user updates notification preferences When email notifications are disabled Then in-app notifications remain enabled, and all notification events are logged in the audit trail

SlideSync Anchors

Detects slide transitions via OCR and visual fingerprinting, then pins chapters to exact slide titles and numbers. Auto-corrects drift between audio and visuals and provides one-click navigation across slides, chapters, and timestamps—eliminating tedious matching and giving learners crisp context.

Requirements

Slide Transition Detection Core
"As an educator, I want automatic detection of slide changes in my lecture videos so that I don’t have to manually scrub to find where each new slide begins."
Description

Implement a robust detection pipeline that identifies slide boundaries in long-form video using a hybrid of visual fingerprinting (frame differencing, perceptual hashes, template matching) and OCR cues (title region changes, page numbers). The pipeline must operate on varied inputs (screen recordings, webcam + screen composites, low-light projectors) and support 16:9 and 4:3 aspect ratios at 24–60 fps. Provide configurable sensitivity thresholds, real-time or near–real-time operation (<1.5x video duration), and batching for asynchronous processing. Emit precise timestamps for slide-in and slide-out, with per-boundary confidence scores, and gracefully fall back to secondary detectors when primary signals are weak. Results must be deterministic given the same input and versioned for reproducibility within ClipSpark’s processing framework.

Acceptance Criteria
Hybrid Boundary Detection Accuracy across Modalities
Given a labeled test suite with at least 3 hours of content spanning screen recordings, webcam+screen composites, and low-light projector videos When the Slide Transition Detection Core runs with default settings Then the detected slide boundaries shall achieve precision ≥ 0.92 and recall ≥ 0.90 overall and within each modality And the false-positive rate due to within-slide animations/transitions shall be ≤ 0.05 per hour of video And all files complete without crash or skip (completion rate = 100%)
Timestamp Precision and Confidence Emission
Given ground-truth slide-in and slide-out times labeled to the nearest 100 ms When the pipeline outputs boundaries Then each boundary includes slide_in_time_ms, slide_out_time_ms, and confidence ∈ [0.0, 1.0] with at least 2-decimal precision And absolute timestamp error ≤ 200 ms at median and ≤ 500 ms at p95 versus ground truth And applying a confidence filter ≥ 0.80 increases precision by ≥ 5 percentage points while reducing recall by ≤ 10 percentage points on the test suite
Throughput and Asynchronous Batching
Given a 60-minute 1080p video When processed end-to-end excluding upload/download time Then total processing time ≤ 90 minutes (≤ 1.5× video duration) Given a batch submission of 25 videos totaling ≥ 20 hours of content When submitted to the batch API Then jobs are accepted and processed asynchronously, each assigned a job_id, results persisted, at least 4 jobs processed concurrently, and average per-video processing time across the batch remains ≤ 1.5× video duration
Configurable Sensitivity and Deterministic Reproducibility
Given a configuration for visual_delta_threshold, ocr_confidence_threshold, and min_slide_duration_ms When values are adjusted and the pipeline rerun Then detection outcomes change accordingly and the effective parameters are recorded in the output metadata Given identical input video, identical configuration, and identical pipeline version When the pipeline is run twice Then the outputs (boundaries, timestamps, confidences) are byte-for-byte identical And the output includes version metadata: pipeline_version, model_hashes, and config_digest
Aspect Ratio and Frame Rate Coverage
Given input videos with aspect ratios 16:9 and 4:3 at frame rates 24, 30, and 60 fps When processed by the pipeline Then processing completes without error for each combination and meets the accuracy and timestamp precision criteria for each And any resampling or normalization is captured in output metadata (e.g., effective_fps)
Graceful Fallback under Weak Primary Signals
Given segments where visual fingerprint deltas remain below the primary threshold for ≥ 2 seconds and OCR detects title/page-number change with confidence ≥ 0.85 When processed by the pipeline Then a slide boundary is emitted with confidence reflecting the OCR signal and metadata indicates fallback_detector_used = true Given a low-contrast projector subset where visual-only recall ≤ 0.60 When the hybrid pipeline with fallback is used Then recall improves to ≥ 0.85 while maintaining precision ≥ 0.88 on that subset
Title & Number OCR Normalization
"As a knowledge worker, I want slide titles and numbers extracted reliably so that chapters can be labeled clearly and searched easily."
Description

Extract slide titles and slide numbers using OCR with language auto-detection and noise tolerance (compression artifacts, low contrast). Normalize numbering schemes (e.g., 1, 1.1, I, A-12) and map them to a canonical sequence. Implement text region localization to prioritize likely title and number areas and fuse multiple frames around transitions to boost OCR accuracy. Support at least Latin-based languages at launch with extensible language packs. Provide de-duplication and fuzzy-matching to handle minor title variations across slides, and expose a normalized title/number field for anchoring and UI display within ClipSpark.

Acceptance Criteria
Noisy Conditions Title OCR Accuracy
Given a validation set of 20 long-form videos (≥200 distinct slides) encoded with compression artifacts and low-contrast slides When OCR with region localization and language auto-detection is executed Then extracted slide titles must achieve ≥93% exact-match accuracy and ≥97% token-level F1 against ground truth And the title miss rate (no title returned) is ≤2% And false-positive title rate (non-title text labeled as title) is ≤3%
Latin Language Auto-Detection and OCR
Given slides containing titles in English, Spanish, French, German, Portuguese, Italian, Dutch, and Polish When language auto-detection runs prior to OCR Then the selected language must match the ground-truth language for ≥95% of titles with confidence ≥0.8 And per-language title exact-match accuracy is ≥90% And when confidence <0.5, the default Latin pack is used and the title exact-match accuracy remains ≥85%
Slide Number Normalization Across Schemes
Given a deck containing number formats: "1", "001", "1.1", "I", "IV", "A-12", "2/12", and slides without visible numbers When number extraction and normalization runs Then normalizedNumber is a strictly increasing integer sequence starting at 1 in presentation order And detection precision and recall for visible numbers are each ≥98% on the validation set And Roman numerals up to L (50), dotted decimals up to three levels (e.g., 3.12.4), and alphanumeric prefixes (A–Z) are correctly parsed And slides without visible numbers are assigned the next normalizedNumber without breaking sequence
Title/Number Region Localization Effectiveness
Given standard slide layouts where titles are in the top 30% and numbers in the top-right or bottom-right corners When region-localized OCR is applied Then ≥95% of title bounding boxes fall within the top 30% of the frame And ≥95% of number bounding boxes fall within a 15% corner area And compared to full-frame OCR baseline, non-title false positives are reduced by ≥50% on the validation set
Multi-Frame Fusion at Transitions
Given detected slide transitions with motion blur or compression smearing When OCR results are fused across ±5 frames around the transition Then title exact-match accuracy improves by ≥5 percentage points versus single-frame OCR on the same set And number extraction accuracy improves by ≥3 percentage points And fusion does not introduce duplicate titles for a single slide (duplication rate ≤1%)
Title De-duplication and Fuzzy Matching
Given consecutive or near-consecutive slides with minor title variations (casing, punctuation, whitespace, or edit distance ≤2 for titles ≤60 chars) When normalization and de-duplication are applied Then such slides resolve to a single normalizedTitle And de-duplication precision is ≥98% and recall is ≥95% on a labeled set of ≥300 slide pairs And titles with semantic or edit distance >3 are not merged (false-merge rate ≤1%)
Normalized Fields Exposed for Anchoring and UI
Given a processed video When SlideSync Anchors are requested via the ClipSpark API Then each anchor includes non-null normalizedTitle and normalizedNumber fields alongside raw OCR outputs and timestamps as defined in the API schema And normalizedNumber aligns 1:1 with slide order used by navigation components And ClipSpark UI displays normalizedTitle/normalizedNumber consistently in slide, chapter, and timestamp views without mismatch across components
Audio-Visual Drift Auto-Correction
"As a podcaster who records slides and narration separately, I want the system to auto-fix drift so that the chapters match what I’m talking about at the right moment."
Description

Align spoken transcript segments with detected slide anchors and correct drift between audio and visual tracks. Implement cross-modal alignment using CTC or DTW-style time warping, constrained by detected boundaries and transcript punctuation. Enforce maximum shift limits (e.g., ±2.0 seconds by default) and confidence-aware adjustments to avoid overshooting. Provide per-anchor alignment deltas and a global drift score, with safeguards when audio or video is missing. Persist corrections in ClipSpark’s timeline model and expose before/after timestamps for auditability and rollback.

Acceptance Criteria
Anchor-Constrained Drift Correction Within ±2s
Given a video with detected slide anchors and a transcript with segment boundaries When auto-correction runs with default maxShiftSeconds = 2.0 Then the absolute shift applied to each segment start and end is ≤ 2.0 seconds And adjusted segments assigned to a slide remain fully within that slide’s [start, end] window And segment timestamps remain non-overlapping and strictly monotonically increasing And all adjusted timestamps remain within the media duration [0, video_length]
Confidence-Aware Adjustment Limits
Given per-segment alignment confidence in [0.0, 1.0] and thresholds T=0.60 and lowCap=0.50s When auto-correction runs Then for segments with confidence < T, the absolute shift applied is ≤ 0.50 seconds And for segments with confidence ≥ T, the absolute shift applied is ≤ maxShiftSeconds And if both audio and visual confidences < 0.40, the segment receives no shift (0.00 seconds) And the reason code for any capped or skipped adjustment is recorded per segment
Per-Anchor Deltas and Global Drift Score Output
Given N detected slide anchors with before and after timestamps When processing completes Then a per-anchor delta (after - before) in seconds with precision 0.01 is produced for each anchor And a global drift score = mean absolute per-anchor delta is computed and stored And the per-anchor deltas and global drift score are exposed via API and retrievable via project metadata And repeated runs with identical inputs produce identical deltas and drift score
Punctuation-Constrained Time Warping
Given a tokenized transcript with sentence-level punctuation boundaries [.?!,;:] When alignment adjusts segment boundaries Then new segment boundaries occur only at punctuation boundaries or at original boundaries And no word token is split across two timestamps And word-level time mappings remain ordered and non-overlapping
Missing Modality Safeguards
Given an input where either the audio track is unavailable/corrupted or slide detection yields zero anchors When auto-correction runs Then no timestamp shifts are applied to any segment (absolute shift = 0.00 seconds) And the global drift score is null and a "missing_modality" flag is stored And the process completes without error and returns a successful result code And before and after timestamps are identical for all segments
Persistence, Audit Trail, and Rollback
Given corrected timestamps for all segments When the timeline is persisted Then each segment record stores before_start, before_end, after_start, after_end with precision 0.01s And an audit record captures algorithm version, parameters (maxShiftSeconds, thresholds), run ID, and timestamp And invoking rollback restores all segments to their before_* values and marks the corrected version as superseded And after rollback, a re-run creates a new audit record without duplicating superseded entries
Configurable Max Shift Limits
Given a project setting maxShiftSeconds with allowed range [0.0, 5.0] and default 2.0 When a user attempts to set maxShiftSeconds outside the allowed range Then validation fails and the previous valid value remains in effect And when set within the range, the algorithm uses the configured value and records it in the audit record And per-segment and per-anchor adjustments do not exceed the configured maxShiftSeconds
Chapter Anchoring & Merge Rules
"As an instructional designer, I want clean chapters anchored to meaningful slides so that learners can jump to the right section without noise or duplicates."
Description

Generate chapters pinned to exact slide titles and numbers, applying rules to merge rapid-fire slides (below a configurable duration threshold) and to skip duplicate or near-duplicate slides (e.g., agenda/section divider repeats). Provide heuristics for combining title-only slides with subsequent content slides and allow minimum chapter length settings. Ensure anchors remain stable when upstream detection updates occur by using anchor IDs and idempotent update logic. Output a clean, human-readable chapter list ready for publishing and export within ClipSpark.

Acceptance Criteria
Exact Slide Title and Number Anchoring
Given a recording with a slide deck where each slide has a visible number and title and SlideSync processing is enabled When chapters are generated Then each chapter start_time aligns with the exact video frame of the corresponding slide transition within ±200ms And each chapter includes slide_number matching the detected slide index and slide_title matching OCR text with confidence ≥ 0.95 or normalized Levenshtein distance ≤ 2 And each chapter contains a unique anchor_id (UUID) that is stable across reprocessing with identical inputs And the number of chapters equals the count of unique slides after applying merge and dedupe rules
Merge Rapid-Fire Slides Below Threshold
Given merge_threshold_seconds = 2.0 and a sequence of three consecutive slides with durations 1.3s, 1.1s, and 0.8s When chapters are generated Then the three slides are merged into a single chapter anchored at the first slide’s start_time And the resulting chapter duration equals the sum of the three slide durations ±200ms And the chapter title is taken from the first non-title-only slide in the merged group And only one chapter entry is created for the group and the other slides do not appear as separate chapters
Skip Duplicate or Near-Duplicate Slides
Given similarity_threshold = 0.93 and an input where slide i and slide j are near-duplicates (visual fingerprint cosine ≥ 0.93 or OCR similarity ≥ 0.93) occurring within the same session When chapters are generated Then only the first occurrence produces/retains a chapter and later duplicates are skipped And skipped slides are recorded in the processing log with slide indices and similarity scores And no chapter timestamps are created for skipped slides
Combine Title-Only Slides With Following Content
Given title_only_heuristics enabled (text length < 40, no bullets/figures, and/or regex matches: ^(Agenda|Overview|Section \d+)$) And a title-only slide immediately precedes a content slide within 15s When chapters are generated Then a single chapter is produced that starts at the title-only slide’s start_time and ends at the end of the content slide And the chapter title uses the content slide’s title And the chapter’s anchor_id is that of the title-only slide; the content slide does not produce a separate chapter
Minimum Chapter Length Enforcement
Given min_chapter_length_seconds = 30 And initial chapterization produces chapters of durations [12s, 18s, 45s, 22s] When minimum length enforcement runs after merge/dedupe/title-only rules Then chapters shorter than 30s are merged forward into the next chapter, except the final short chapter which merges backward And the final chapter set contains no chapter with duration < 30s And chapter ordering and start_time monotonicity are preserved with no overlaps
Anchor ID Stability and Idempotent Update
Given an existing published chapter list with anchor_ids [A1…An] And upstream slide detection is re-run producing boundary shifts ≤ ±500ms and one split/merge change When the system reprocesses with the same configuration Then the set of chapter anchor_ids remains identical [A1…An] and is mapped to the updated boundaries And no duplicate or new anchor_ids are created And repeated reprocessing yields an identical chapter list (byte-for-byte in JSON export) when inputs are unchanged
Clean, Human-Readable Chapter List Export
Given a chapterized recording ready for publishing When the chapter list is rendered in-app and exported Then the in-app list displays ordered chapters with fields: index, slide_number, slide_title, start_time, end_time, duration, anchor_id And JSON and CSV exports are produced with the same records and ISO-8601 or hh:mm:ss.sss time formats respectively And chapters are strictly sorted by start_time, non-overlapping, and cover the full video duration ±1s at the tail And titles are sentence-cased, trimmed, and free of OCR artifacts (no double spaces, no leading/trailing punctuation)
One-Click Slide Navigation UI
"As a learner, I want to click a slide title and jump immediately to that moment so that I can review specific concepts quickly."
Description

Deliver UI components enabling instant navigation across slides, chapters, and timestamps: a synchronized slide list with titles/numbers, thumbnail previews, and a seek-on-click behavior (<150 ms seek initiation). Include keyboard shortcuts, tooltip timestamps, and deep-link copy for any slide anchor. Ensure responsive performance on desktop and mobile, WCAG AA accessibility (focus states, ARIA roles), and internationalization support for right-to-left languages. Integrate seamlessly with ClipSpark’s player, respecting existing caption and highlight overlays.

Acceptance Criteria
One-Click Slide Seek and Overlay Integrity
Given a video has SlideSync Anchors computed and the slide list is visible When the user clicks a slide title or thumbnail in the list Then the player initiates a seek within <=150 ms and lands within ±250 ms of the target anchor timestamp And the active slide selection updates and is visually highlighted within <=200 ms And each slide item displays its slide number and title; if the title is missing, a default label "Slide {N}" is shown And caption and highlight overlay positions/z-order are unchanged pre/post seek (pos delta <=1 px; occlusion area by navigation UI = 0 px^2) And when playback crosses a slide boundary during normal play, the active slide selection updates within <=200 ms without user action
Thumbnail Previews and Tooltip Timestamps
Given the slide list is visible on a pointer device When the user hovers a slide item or keyboard-focuses it Then a thumbnail preview appears within <=200 ms showing a frame from within ±1 s of the anchor timestamp at >=160x90 logical pixels (DPR-aware) And a tooltip shows the slide title, slide number, and localized HH:MM:SS timestamp And on touch devices, a 500–800 ms long-press shows the same preview/tooltip and dismisses on outside tap or navigation And subsequent previews of the same item load within <=100 ms via cache
Keyboard Navigation Shortcuts for Slides and Chapters
Given the player has focus When the user presses "]" then next slide is selected and seek initiated; "[" selects previous slide; "Shift+]" selects next chapter; "Shift+[" selects previous chapter Then each action initiates seek within <=150 ms and updates active selection within <=200 ms And all actions are operable without a pointing device, with visible focus indicators meeting >=3:1 contrast And a keyboard help dialog is available via "?" that lists these shortcuts with ARIA semantics And no shortcut overrides browser/OS-reserved keys; if a conflict is detected, the app displays a remapping prompt and an alternative binding is applied
Deep-Link Copy for Slide Anchors
Given a slide item is visible When the user activates "Copy link" or presses Cmd/Ctrl+C while the item is focused Then a deep link in the format {baseUrl}?v={videoId}&slide={slideNumber}&t={timestampMs} is copied to the clipboard And a non-blocking confirmation toast appears within <=1500 ms And opening the deep link in a fresh session loads the video, seeks within ±250 ms of the anchor, and highlights the slide And if clipboard permission is denied, a fallback modal with the link in a selectable text field is shown
Responsive Desktop and Mobile Performance
Given a mid-tier mobile device (e.g., 4-core CPU, 2–3 GB RAM) on a 3G/4G network When the One-Click Slide Navigation UI is opened Then First Input Delay <=100 ms and the slide list becomes interactive within <=2 s And visible content exhibits CLS <=0.05 And tap targets are >=44x44 px and scrolling the list maintains >=60 FPS And with 1,000 slides, memory usage attributable to the list stays <100 MB via virtualization And rotating the device reflows layout within <=300 ms without clipping or unintended horizontal scroll
WCAG 2.1 AA Accessibility Compliance
Given a screen reader (NVDA/JAWS/VoiceOver) is active When the user navigates the UI Then all interactive elements expose correct roles, names, and states; each slide announces number, title, and timestamp And focus order follows visual order with no traps; a "Skip to slide list" link is available And text contrast >=4.5:1; non-text and focus indicators >=3:1 with a visible outline >=2 px And all core actions (seek, preview, deep-link copy, shortcut help) are fully operable via keyboard/screen reader
Right-to-Left (RTL) Internationalization Support
Given the app locale is set to an RTL language (e.g., ar, he, fa) When the One-Click Slide Navigation UI renders Then layout and iconography are mirrored; slide numbers and controls align to the right; tooltips anchor appropriately And dir attributes are applied to ensure proper bidi rendering; mixed-direction titles are isolated to prevent character reordering And numerals and timestamps follow locale conventions where applicable And keyboard semantics remain consistent ("]"/"[" shortcuts unchanged unless remapped); arrow key navigation respects visual order And deep links remain locale-neutral and restore the correct anchor in any locale
Sync API & Deep-Linking Endpoints
"As a platform integrator, I want reliable APIs and deep links to slide anchors so that I can embed precise navigation in my LMS and notes apps."
Description

Expose REST/GraphQL endpoints to retrieve slide anchors, titles, numbers, confidence, drift deltas, and chapter structures. Support webhooks/callbacks when processing completes and include stable deep-link formats (e.g., /v/{id}?slide=12 or ?t=00:05:32) that resolve to corrected timestamps. Provide pagination, filtering by confidence or time range, ETag/versioning for cache validation, and access control aligned with ClipSpark’s auth model. Offer SLA-friendly error handling and rate limits, plus OpenAPI/SDL documentation for partner integrations.

Acceptance Criteria
Retrieve Slide Anchors via REST and GraphQL
Given a processed video id and a valid bearer token with scope videos:read, when GET /api/v1/videos/{id}/anchors is called, then the response status is 200 and the body contains an array anchors[]. And each anchor item includes: anchorId (UUID), slideNumber (integer >= 1), slideTitle (non-empty string), startMs (integer >= 0), correctedStartMs (integer >= 0), driftDeltaMs (integer, may be negative), confidence (number between 0 and 1 inclusive, rounded to 2 decimals), chapterId (string), chapterTitle (string). And correctedStartMs equals startMs + driftDeltaMs within ±50ms tolerance. And the anchors are sorted by correctedStartMs ascending. And GET /api/v1/videos/{id}/chapters returns 200 with chapters[] each having: chapterId (UUID), chapterTitle (non-empty string), startMs (integer >= 0), correctedStartMs (integer >= 0). And an equivalent GraphQL query video(id: ID!) returns fields anchors { anchorId slideNumber slideTitle startMs correctedStartMs driftDeltaMs confidence chapterId chapterTitle } and chapters { chapterId chapterTitle startMs correctedStartMs } with identical values. When the video id does not exist, then REST returns 404 with error.code = "VIDEO_NOT_FOUND" and GraphQL returns errors[0].extensions.code = "VIDEO_NOT_FOUND".
Deep-Link Resolution to Corrected Timestamps
Given an existing video with detected slide anchors, when GET /api/v1/videos/{id}/resolve?slide=12 is called by an authorized client, then the response is 200 with JSON containing slide=12, correctedStartMs (integer >= 0), and anchorId (UUID) that matches the slide 12 anchor. And when GET /api/v1/videos/{id}/resolve?t=HH:MM:SS(.mmm) is called, then the response is 200 with JSON containing inputT, nearestAnchorId (UUID), requestedMs (parsed from t), and correctedStartMs representing the drift-corrected seek position. And when a public deep link /v/{id}?slide=12 is requested, then the server responds 302 Found to /v/{id}?t=HH:MM:SS.mmm where t equals correctedStartMs formatted to milliseconds. When the slide parameter does not correspond to any anchor, then the API returns 400 with error.code = "SLIDE_NOT_FOUND". When the t parameter cannot be parsed, then the API returns 400 with error.code = "INVALID_TIME_FORMAT".
Processing Completion Webhook Delivery
Given a partner has registered a webhook with eventType = "slidesync.completed" and a shared secret, when slide/anchor processing for a video completes, then the system POSTs to the callback URL within 2 minutes at p95 with JSON payload including: eventId (UUID), eventType = "slidesync.completed", occurredAt (RFC3339), videoId, version (integer >= 1), anchorsCount (integer >= 0), chaptersCount (integer >= 0), and resourceUrl(s) to fetch anchors/chapters. And the request includes headers: X-ClipSpark-Signature (HMAC-SHA256 over the raw body using the shared secret), X-Idempotency-Key (UUID), and Content-Type: application/json. And the receiver returning any 2xx acknowledges delivery; any non-2xx triggers retries with exponential backoff (at least 6 attempts over up to 24 hours) using the same X-Idempotency-Key. And duplicate deliveries (same X-Idempotency-Key) must be safe to apply multiple times by the consumer. When the callback endpoint is unreachable, then retries proceed per backoff schedule and delivery attempts are recorded and queryable via GET /api/v1/webhooks/deliveries?videoId={id}.
Pagination and Filtering by Confidence and Time Range
Given many anchors exist for a video, when GET /api/v1/videos/{id}/anchors?limit=50 is called, then the response includes up to 50 items and a nextCursor when more data remains, with items ordered by correctedStartMs ascending. And limit supports 1..100; values outside this range return 400 with error.code = "INVALID_PAGINATION". And when GET /api/v1/videos/{id}/anchors?cursor={nextCursor} is called, then the next page is returned with the same ordering and no duplicates across pages. And when filters confidenceGte and time range are supplied (e.g., ?confidenceGte=0.85&startMs=120000&endMs=300000), then only anchors with confidence >= 0.85 and correctedStartMs within [120000, 300000] are returned. And equivalent GraphQL arguments (limit, afterCursor, confidenceGte, startMs, endMs) return consistent results with the REST API.
ETag and Versioning for Cache Validation
Given anchors have been computed, when GET /api/v1/videos/{id}/anchors is called, then the response includes ETag (strong) and Last-Modified headers and a version field (integer) in the JSON body. When the same resource is requested with If-None-Match set to the current ETag, then the server responds 304 Not Modified with an empty body. When reprocessing updates any anchor or chapter (content or ordering), then version increments by 1 and a new ETag is produced; If-None-Match with the prior ETag returns 200 with the updated body. And caching directives are Cache-Control: public, max-age=60 for completed resources; while processing is in-progress, GET /anchors returns 202 Accepted with processing=true and Cache-Control: no-cache.
Authorization, Access Control, and Rate Limits
Given an API request without Authorization, when accessing any Sync API endpoint under /api/v1/videos/{id}, then the server returns 401 with error.code = "UNAUTHENTICATED". Given a JWT bearer token lacking the videos:read scope or lacking access to the target video (not owner/collaborator and video not public), when accessing anchors/chapters, then the server returns 403 with error.code = "FORBIDDEN". Given a public video, when requesting deep links under /v/{id}?slide= or ?t=, then resolution succeeds without authentication; private videos require authentication and otherwise return 403. When a client exceeds the rate limit of 1000 requests per minute with bursts up to 200, then the server returns 429 Too Many Requests with headers X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, and Retry-After (seconds). All error responses follow a standard envelope: { "error": { "code": string, "message": string, "details": object, "requestId": string } } with unique requestId per response.
OpenAPI and GraphQL Schema Documentation
Given the Sync API is deployed, when GET /docs/openapi.json is called, then an OpenAPI 3.1 document describing all Sync endpoints (anchors, chapters, resolve, webhooks, deliveries) is returned with no schema validation errors and includes request/response examples and error schemas. And when GET /docs/schema.graphql is called, then the GraphQL SDL is returned including types Video, Anchor, Chapter, and queries video(id: ID!) and anchors(videoId: ID!, filters, pagination) with field descriptions matching REST semantics. And human-readable docs are available at /docs with authentication instructions, deep-link format examples (/v/{id}?slide=12, /v/{id}?t=00:05:32), webhook signature verification steps, and rate-limit header explanations. And documentation reflects the current deployed version (version string and date) and is updated within one release of any schema change.

Quiz Seedsmith

Expands quiz seeds into complete, well-formed items (MCQ, T/F, short answer) with plausible distractors, targeted feedback, and difficulty levels. Tags each item to objectives and chapters, and exports to QTI/xAPI or directly to LMS banks—speeding assessment creation while preserving alignment.

Requirements

Seed-to-Item Expansion Engine
"As an educator, I want to turn brief prompts into full quiz questions so that I can build assessments quickly without sacrificing quality."
Description

Transform a concise quiz seed into fully structured assessment items (MCQ, True/False, and Short Answer) with validated stems, correct answers, rationales, and assigned difficulty levels. The engine ingests ClipSpark’s transcript segments, topic summaries, and highlights to ground questions in accurate, context-rich material. It enforces item-writing best practices (clarity, reading level, no double negatives), supports language consistency with the source media, and provides deterministic/regenerable outputs via guardrailed AI prompts and schemas. Items are versioned, idempotent on the same seed/context, and include metadata such as source video, segment IDs, and authoring timestamps to enable auditability and downstream export.

Acceptance Criteria
Seed expansion yields complete item set for a single seed
Given a quiz seed with configured output types (MCQ, True/False, Short Answer) and supplied context (transcript segments, topic summary, highlights) When the Seed-to-Item Expansion Engine processes the seed Then it produces exactly 1 MCQ, 1 True/False, and 1 Short Answer item And each item includes: a non-empty stem (<= 30 words), correct answer(s), a rationale (>= 20 words), a difficulty level in {Easy, Medium, Hard}, itemId, and version And the MCQ has exactly 4 options with 1 correct option, no duplicate options, and each option length is 5–80 characters And the Short Answer includes a model answer (<= 50 words) and at least 3 rubric keywords And the True/False item specifies a single boolean correctAnswer and contains no qualifiers that make it ambiguous (e.g., always, never)
Grounding and provenance to ClipSpark transcript segments
Given transcript segments and highlight timestamps associated to the seed When the engine generates items Then each item metadata contains sourceVideoId, at least 1 segmentId, and optional start/end timestamps when derived from highlights And any quoted text in stems, options, feedback, or rationales must match verbatim text within the referenced segment(s) And each item rationale includes at least one explicit reference to the supporting segmentId(s) And items lacking verifiable supporting segments are rejected with error code UNVERIFIED_SOURCE and are not included in the output
Item-writing best practices and readability compliance
Given the engine has produced items When the items are validated by the item-writing linter Then 0 critical errors and 0 warnings are reported for: double negatives, trick wording, vague pronouns, and biasing language And MCQs contain no options such as “All of the above” or “None of the above” and avoid overlapping option validity And stems are clear, self-contained, and free of unnecessary context; readability score targets Grade 7–10 inclusive (e.g., FKGL 7–10 or equivalent) for general-audience content And difficulty labels are consistent with rubric rules (e.g., Easy = recall, Medium = application, Hard = analysis) based on detected cognitive verbs in stems
Deterministic and idempotent generation
Given identical inputs (seed text, context set, configuration parameters, and promptModelVersion) When generation is executed multiple times Then the canonical item JSON outputs are byte-identical, including itemId, content fields, difficulty, and createdAt timestamp And the contentHash computed over canonicalized item JSON is identical across runs And given any change to seed, context, or promptModelVersion Then the item contentHash changes and the version increments by at least a minor version (e.g., 1.2.0 -> 1.3.0)
Versioning and metadata completeness
Given items are created or updated When the engine writes item metadata Then each item includes: itemId (deterministic UUIDv5 from seedHash+type+sourceVideoId), version (SemVer), createdAt (ISO 8601 UTC), updatedAt (ISO 8601 UTC), authorId, promptModelVersion, seedHash, language (BCP-47), sourceVideoId, segmentIds[], and exportable=true|false And version increments follow: major for schema changes, minor for stem/options/answers/rationale/difficulty changes, patch for metadata-only changes And items missing any required metadata fields are rejected with error code METADATA_INCOMPLETE
Standards-compliant exports (QTI and xAPI) and LMS bank delivery
Given a generated item set When the user exports to QTI Then the package validates against the QTI 2.2 XML schema with 0 validation errors and 0 warnings And when exporting to xAPI Then statements validate against the xAPI 1.0.3 schema, including actor, verb, object, result (with success), and context linking to sourceVideoId and segmentIds And when pushing directly to a configured LMS item bank via API Then the API responds 201 Created with the expected item count, and a subsequent GET returns items with matching hashes and metadata
Language consistency with source media
Given a seed linked to a source media language (e.g., en-US) or an explicit target language override When the engine generates items Then stems, options, feedback, and rationales are produced in exactly the target language and locale And automated language detection on the concatenated item text reports >= 95% confidence for the target language with no secondary language above 5% And number formatting and punctuation follow the locale conventions of the target language And any technical terms retained in original language are italicized or quoted and explained in feedback or rationale
Contextual Distractor Generation
"As an instructional designer, I want believable distractors aligned to the video content so that my MCQs measure understanding rather than test-taking tricks."
Description

Generate plausible, content-anchored distractors that reflect common misconceptions and near-miss concepts extracted from ClipSpark’s transcript analysis and topic graph. The module ensures semantic distinctness from the key, avoids giveaway cues (length, absolutes, grammatical mismatches), and adheres to configurable constraints (count, reading level, similarity thresholds). It runs correctness checks, bias/offensiveness screens, and duplication detection across an item set. Outputs include per-distractor rationales and metadata linking back to transcript evidence, enabling reviewers to trace why each distractor is plausible.

Acceptance Criteria
Configurable Count and Reading Level Compliance
Given a seed item with configured distractor_count=3 and reading_level_grade=9 When the system generates distractors Then exactly 3 distractors are produced And each distractor's Flesch-Kincaid Grade Level <= 9.0 And the standard deviation of distractor lengths (characters) <= 0.2 * the mean length And no distractor contains spelling errors (spell-check confidence >= 0.99)
Semantic Distinctness From Key Within Thresholds
Given a correct answer key and max_similarity_to_key=0.75 When distractors are generated Then cosine similarity between each distractor and the key <= 0.75 And cosine similarity between any pair of distractors <= 0.85 And token overlap with the key (excluding stopwords) <= 50% And textual entailment probability that a distractor entails the key < 0.2
No Giveaway Cues and Parallel Grammar
Given a multiple-choice item with 1 key and N distractors When options are finalized Then no distractor contains absolute terms (e.g., always, never, all, none) unless present in the stem And option lengths (words) are within +/-25% of the mean length And all options share the same syntactic form (all sentence fragments or all complete sentences) And tense and person are consistent across all options And capitalization and punctuation style is consistent across all options
Per-Distractor Rationale with Traceable Transcript Evidence
Given an item generated from a ClipSpark transcript When distractors are output Then each distractor includes a 1–2 sentence rationale describing the misconception or near-miss And each rationale includes at least one transcript evidence reference with video_id and start_ms/end_ms And the evidence snippet matches the transcript text at those timestamps with >= 80% character overlap And topic_graph node IDs and relation types used for sourcing are included And distractor metadata includes {misconception_tag, difficulty, reading_level_grade, similarity_to_key, evidence_refs[]} per distractor
Correctness, Bias, and Offensiveness Screening
Given generated distractors and the aligned objective When validation runs Then no distractor is factually correct with respect to the transcript and objective (entailment to ground truth < 0.2) And any distractor flagged as potentially correct is auto-regenerated up to 2 times; failing that, the item is marked 'Needs Review' And each distractor passes bias/offensiveness screening with status 'clear' And any distractor flagged 'risky' is replaced before export And all validation results are written to metadata with validator name and timestamp
Cross-Item Duplication and Paraphrase Control
Given a batch of M items When duplication detection runs Then no distractor has cosine similarity > 0.90 to any other distractor in the batch And no distractor reuses wording within the same item (pairwise similarity within item <= 0.85) And no distractor duplicates one used for the same objective/chapter in the past 90 days (per history index) And on detection, the system regenerates up to 2 times; failing that, flags the item for review And a de-duplication report is stored with affected item_ids and action_taken
Misconception-Driven Distractor Sourcing from Topic Graph
Given a seed aligned to objective O and topic graph G When distractors are generated Then at least 2 distractors cite misconceptions detected in the transcript with occurrence_count >= 2 And at least 1 distractor comes from a sibling or prerequisite node within 2 hops of O in G And each distractor's rationale explicitly names the source concept and relation_type And sourcing metadata includes concept_node_id and occurrence_count >= 1
Targeted Feedback & Hints
"As a teacher, I want targeted feedback tied to each answer so that students learn from mistakes and understand the correct concept."
Description

Produce targeted feedback for each answer choice and general item feedback, explaining why options are correct or incorrect and pointing learners to precise, timestamped video segments for remediation. Feedback tone and depth are configurable (formative vs. summative), and hint generation can be enabled for partial scaffolding without revealing answers. Outputs support lightweight HTML/Markdown for LMS display, meet accessibility guidelines (concise, screen-reader friendly), and are packaged for export alongside items with stable references to ClipSpark highlights.

Acceptance Criteria
Formative feedback with targeted remediation links
Given a multiple-choice item with formative tone enabled and ClipSpark highlight mappings available When the item is generated Then each answer choice includes feedback of 1–3 sentences (max 120 words) explaining why it is correct or incorrect And each feedback contains at least one remediation deep link to a ClipSpark highlight with timestamp in HH:MM:SS And the deep link seeks to within ±1 second of the referenced timestamp in the supported LMS preview And the reading level of each feedback is grade 9 or lower (Flesch–Kincaid)
Summative tone with minimal feedback and no hints
Given summative tone is enabled and hints are disabled for an item When the item is generated Then per-choice feedback is limited to a single concise sentence (≤ 25 words) without remediation links And general item feedback includes exactly one remediation link to the most relevant ClipSpark highlight And the export contains no hint elements or placeholders
Per-choice targeted feedback across item types
Given a seed expanded into MCQ, True/False, and Short Answer items When targeted feedback is generated Then MCQ includes per-option feedback for all options, including distractors And True/False includes distinct feedback for both true and false selections And Short Answer includes feedback for the correct response and at least three common incorrect patterns And where applicable, feedback references the specific concept or video segment used to explain the rationale
Lightweight HTML/Markdown rendering in LMS
Given feedback and hints must render in an LMS supporting basic HTML/Markdown When exported and previewed in the LMS Then only the following HTML tags are emitted: p, strong, em, a, ul, ol, li, code, br And all links use descriptive text (no “click here”/“this”) And content contains no inline styles, scripts, iframes, or images And Markdown and HTML variants render equivalently in the LMS preview
Hints provide scaffolding without revealing answers
Given hints are enabled and tone is formative When hints are generated for an item Then provide 1–2 progressive hints per item And no hint contains the exact correct answer text or a unique key phrase (case-insensitive substring check) And hints reference concepts or chapters but do not quote the exact sentence containing the answer And each hint is ≤ 20 words and at grade 8 reading level or lower
Accessibility and screen-reader friendliness
Given feedback and hints will be read by screen-reader users When tested with NVDA or JAWS in Chrome Then the reading order follows the visual order of options and their feedback And list structures and links are announced due to semantic tags And link text is descriptive and unique within the item And each feedback block is ≤ 120 words and avoids emojis or decorative ASCII characters
Export packaging with stable ClipSpark highlight references
Given QTI 2.2 and xAPI exports are requested When the item bank is exported Then each feedback and hint that references remediation includes a stable highlight_id and HH:MM:SS timestamp And re-importing into a target LMS preserves highlight_id mappings and deep links remain functional And the export manifest lists all highlight_ids with corresponding item IDs and option IDs And QTI/xAPI schema validation passes with zero errors
Objective, Chapter, and Bloom Tagging
"As a curriculum lead, I want each item tagged to objectives and chapters so that assessments remain aligned and easy to organize."
Description

Automatically tag each generated item to course objectives, chapter headings, and cognitive level (e.g., Bloom’s taxonomy) by aligning seed intent with ClipSpark’s topic segmentation and any provided syllabus or standards mappings. Provide manual override, multi-tag support, and confidence scores. Maintain a tag dictionary with versioning, enable search/filter by tags, and propagate tags into exports (QTI metadata, xAPI context). This ensures alignment, eases organization in LMS banks, and supports coverage analytics across objectives and chapters.

Acceptance Criteria
Auto-Tagging with Confidence Scoring and Review Threshold
Given a user generates items from quiz seeds with a syllabus/standards mapping available and topic segmentation enabled When the items are generated Then each item has at least one objective tag, one chapter tag, and exactly one Bloom level tag, all drawn from the tag dictionary And each tag includes a confidence score between 0.00 and 1.00 with two decimal places And if any tag confidence is below the configurable threshold T for the course, the item is placed in the Needs Tag Review queue And chapter and objective tags are selected only from the provided syllabus/standards mapping when present; otherwise from topic segmentation And each tag stores source attribution (auto) and evidence references (e.g., seed intent, timestamp segments)
Manual Override of Tags with Persistence
Given an item with auto-assigned tags is opened in the Review UI When the user adds/removes/reorders objective and chapter tags or edits the Bloom level and clicks Save Then the updated tags are saved with manualOverride=true and the change is reflected immediately in the item detail And subsequent auto-tagging runs do not overwrite manually overridden tags unless the user explicitly selects Re-apply auto-tagging And exports use the manually overridden tags And an audit log records the user ID, timestamp, and before/after tag sets
Multi-Tag Support and Ordering
Given an item may align to multiple objectives and chapters When tags are assigned (auto or manual) Then the system allows up to N objective tags and M chapter tags per item (course-level configurable; defaults N=3, M=2) And Bloom level is single-select per item And tags are stored and displayed in descending confidence order for auto tags, or in user-defined order for manual tags And duplicate tags within a category are prevented
Tag Dictionary Management and Versioning
Given an administrator updates the tag dictionary When tags are added, edited, or retired and a new dictionary version is published Then the dictionary version number increments with a changelog entry capturing the changes And all new auto-tagging operations use the latest dictionary version And each item stores tag IDs with the dictionary version used at assignment time And a migration tool can re-evaluate existing items to the latest version and produce a diff report without altering historical records unless confirmed And retired tags remain resolvable for historical items and are marked deprecated
Search and Filter Items by Tags and Confidence
Given a repository of generated items When a user applies filters for objective(s), chapter(s), Bloom level, include/exclude tags, boolean logic (AND/OR), and confidence range Then only items matching the specified criteria are returned And the first page of results (50 items) loads in under 2 seconds for repositories up to 10,000 items And the UI displays total result count and per-tag facet counts consistent with the applied filters And changing filters preserves current sort and pagination resets to page 1
Export Tags to QTI and xAPI
Given a user exports a selected set of items When exporting to QTI 2.2 Then each item's objective(s), chapter(s), bloomLevel, manualOverride flag, and confidence scores are written as item metadata and the XML validates against the QTI 2.2 schema When exporting to xAPI Then each item's tags are included in context (e.g., contextActivities or extensions) preserving multiple values and confidences, and the JSON validates And sample imports into at least two target LMS/test harnesses complete without tag metadata loss or parse errors
Coverage Analytics by Objective and Chapter
Given a course with tagged items When a user opens Coverage Analytics Then the dashboard displays counts and percentage coverage by objective and by chapter with drill-down to the underlying items And users can set target coverage thresholds per objective/chapter and see gaps highlighted And applied filters (e.g., Bloom level, difficulty) are reflected in coverage metrics And users can export a CSV including objective/chapter IDs, names, counts, percentages, target thresholds, and item IDs
Standards-Compliant Export & LMS Sync
"As an LMS admin, I want to export and sync quiz items to our LMS bank in one click so that instructors can deploy assessments without manual reformatting."
Description

Export items (with media, feedback, tags, and metadata) to QTI 2.2/3.0 packages and emit xAPI statements for delivery/analytics. Provide LTI 1.3 Deep Linking to push items directly into LMS item banks (e.g., Canvas, Moodle, D2L, Blackboard) with secure OAuth, deduplication by external IDs, and version-aware updates. Include validation against QTI/xAPI conformance suites, pre-flight checks (missing media, invalid schemas), and actionable error reporting. Support bulk exports, per-course mappings, and post-sync receipts with item counts and links to LMS destinations.

Acceptance Criteria
Standards-Compliant QTI 2.2/3.0 Export (Media, Feedback, Tags, Metadata)
Given a course containing generated items with media assets, feedback, tags, and metadata and an export format of QTI 2.2 or 3.0 is selected When the user initiates an export Then a single ZIP package is produced containing imsmanifest.xml and all referenced XML/item/media resources And every XML resource validates against the selected QTI schema and passes the corresponding conformance suite without errors And every referenced media file is included and correctly linked by relative path in the XML And item feedback, tags, objectives, difficulty, and chapter metadata are preserved in the package according to the QTI specification And the package imports into Canvas, Moodle, D2L, and Blackboard without validation errors
xAPI Statement Emission to Configured LRS
Given an LRS endpoint, credentials, and xAPI version are configured for the workspace When a user previews, delivers, or syncs an item resulting in an attempt or completion event Then xAPI statements with verbs "attempted" and "completed" are posted to the LRS with 2xx responses And actor, object (stable IRI with externalId), result (score if applicable), and context (courseId, objectives, chapter) fields are populated And statements conform to the xAPI specification and pass the ADL xAPI validator And on transient failure the system retries up to 3 times with exponential backoff and logs correlation IDs
LTI 1.3 Deep Linking Push to LMS Item Banks
Given an LMS platform registration (issuer, client_id, deployment_id, JWKS URL) is configured When the user initiates LTI 1.3 Deep Linking to push selected items to the LMS item bank Then the OIDC login completes and the platform id_token is validated (iss, aud, exp, nonce, signature) And a Deep Linking response is returned containing the selected items with titles, descriptions, and external IDs And the LMS confirms creation or update of items in the item bank and returns item identifiers And the user sees a success summary listing the LMS, item counts created/updated, and deep links to the item bank
Deduplication by External IDs Across Syncs
Given items with stable external IDs already exist in a target LMS/course When the same items are pushed again via export or Deep Linking Then no duplicate items are created in the LMS And items with matching external IDs are identified as existing and routed to the update flow And the sync report shows a count of created=0 and updated>=1 for those items
Version-Aware Updates on Re-sync
Given an item in the LMS originated from ClipSpark with externalId=E and version=V1 When the item is updated in ClipSpark to version=V2 and re-synced to the same LMS/course Then the existing LMS item with externalId=E is updated in place to reflect V2 And the LMS item retains its original LMS identifier and associations (e.g., bank, outcomes) And the sync report records the prior and new versions and a timestamped audit entry
Pre-flight Validation and Actionable Error Reporting
Given a selection of items is queued for export or LMS push When pre-flight validation runs Then missing media, invalid schemas, and configuration gaps are detected before export And each error includes item reference, field/path, severity, and a human-readable fix suggestion And items with errors are blocked from export while items without errors remain selectable And the user can download a validation report (CSV/JSON) listing all issues
Bulk Export with Per-Course Mappings and Post-Sync Receipts
Given multiple courses are mapped to corresponding LMS destinations and a bulk export is requested When the export and sync complete Then a separate standards-compliant package is produced per course or LMS destination as configured And per-course mappings route items to the correct LMS item banks And a post-sync receipt is generated per destination showing created/updated/failed counts and links to LMS destinations And the receipt is stored, downloadable, and emailed to the requester
Timestamped Context Anchoring
"As a learner support coach, I want quiz items linked to exact moments in the lecture so that I can direct students to the relevant explanation."
Description

Associate every item and feedback snippet with precise timestamps and optional highlight clips from the source video, leveraging ClipSpark’s existing caption and highlight pipeline. Store durable references (video ID, segment ID, time range) that survive content edits via timecode mapping. Provide ‘Jump to moment’ links for reviewers and learners, and include these references in exports where supported (xAPI context data; QTI metadata). This grounding improves item validity, speeds review, and enables just-in-time remediation during practice.

Acceptance Criteria
Associate Items and Feedback with Durable Timestamps
Given an item or feedback snippet is created from a source video When the item/snippet is saved Then the system stores videoId, segmentId, startTime, and endTime with ≤33ms precision And startTime < endTime and both fall within the source video duration And the stored reference is immutable and retrievable via API for the item/snippet ID And the same reference is visible in the authoring UI metadata panel
Timecode Mapping Survives Video Edits
Given a referenced source video has been edited (trim/insert/cut) and reprocessed When the author opens an item with a stored reference Then the system resolves the original time range to the new timeline using the mapping table And the resolved anchor deviates ≤200ms from the intended semantic moment as verified against regenerated captions And if resolution confidence <95% or mapping fails, the UI flags the item and prompts re-anchoring with a one-click preview And an audit log records the remap event with old/new time ranges
Jump to Moment in Authoring and Review UI
Given an item displays its timestamped reference When a reviewer clicks “Jump to moment” Then the player opens at startTime minus a 1.0s safety pad (but not <0s) And captions for the anchored segment are auto-highlighted during playback And if a highlight clip exists for the time range, the clip plays; otherwise the full video plays from the anchor And the control is accessible via keyboard and has an ARIA label including the timestamp And closing the player returns focus to the originating control
Learner Remediation with Timestamped Feedback
Given a learner submits an incorrect answer to an item with anchored feedback When feedback is shown Then a “Watch why” link opens the anchored moment (clip preferred; full video fallback) And on return, the learner remains on the same item state And an xAPI statement with verb "experienced" records the playback with context containing itemId, videoId, segmentId, and timeRange And playback start is recorded within 2s p95 of link activation on a standard broadband connection
Export of Anchors to xAPI and QTI
Given a quiz bank containing anchored items and feedback When exporting to xAPI Then each item includes context or extensions with videoId, segmentId, startTime, endTime, and a resolvable deep link URL And the exported statements validate against xAPI 1.0.3 in an LRS conformance check When exporting to QTI 3.0 Then each item includes vendor extension metadata fields for videoId, segmentId, startTime, endTime, and deep link And the resulting package passes IMS QTI validation with zero errors And if the target LMS lacks deep-link playback, a warning is included in export logs while metadata remains intact
Integrity Checks and Broken Reference Handling
Given a stored reference points to a video that is deleted or access-restricted When the item is loaded in authoring or delivery Then the UI displays “Reference unavailable” and disables jump links And a nightly integrity job flags the item, logs error code REF_NOT_FOUND, and notifies owners And re-linking via the fix flow updates the reference and clears the flag And the public API returns HTTP 404 with machine-readable error details for the broken anchor endpoint
Performance and Scale of Anchoring Operations
Given a course with 10,000 anchored items When listing items in the bank Then anchor metadata retrieval adds ≤200ms p95 per page of 50 items When a user activates “Jump to moment” Then video playback begins within ≤2.0s p95 and ≤3.5s p99 on standard broadband And timecode remapping after an edit completes within ≤1.5s p95 for a 2-hour video And bulk export of 1,000 items with anchors completes within ≤5 minutes with zero data loss
Reviewer Workflow & Quality Gates
"As a content reviewer, I want an efficient workflow to validate and edit generated items so that only high-quality, aligned questions are published."
Description

Deliver a review interface and workflow to batch inspect, edit, approve, or regenerate items. Include automated quality checks (answer-key validation, duplicate detection, reading level thresholds, accessibility checks, prohibited content flags) and surface confidence scores with evidence from transcripts. Support role-based permissions, inline editing with schema validation, change history/versioning, comments/mentions, and bulk actions (approve all, regenerate distractors, retag). Only approved items advance to export/sync, ensuring consistent quality and alignment.

Acceptance Criteria
Batch Review Workflow: Inspect, Edit, Approve, Regenerate
- Given a Reviewer opens a batch with 50 items, When the list loads, Then each row displays type, stem preview, answer key indicator, tags, difficulty, status, and confidence score. - Given a Reviewer opens an item, When they edit stem/options/feedback/tags/difficulty, Then schema validation prevents save if required fields are missing or invalid and displays inline errors; When save succeeds, Then a new version is created with a changelog entry. - Given selected items (single or multiple), When the Reviewer clicks Approve, Then status changes to Approved and timestamp/user are recorded. - Given selected items, When the Reviewer triggers Regenerate Distractors, Then new distractors are generated, diffs are shown, and the item remains Unapproved until explicitly approved. - Given a filtered list, When the Reviewer chooses Approve All, Then only items without blocker flags are approved and a summary of skipped items is displayed.
Quality Gates: Answer-Key Validation and Duplicates
- Given an MCQ item, When quality checks run, Then exactly one option must be marked correct; if not, the item is flagged Blocked: Answer Key and cannot be approved. - Given a True/False or Short Answer item, When checks run, Then the correct answer must be logically consistent with the stem (and acceptable variants defined for Short Answer); failures are flagged and block approval. - Given a batch and existing bank, When duplicate detection runs before approval, Then items with similarity score ≥ 0.90 on stem+options are flagged Duplicate with links to matches, and Approve is disabled until the reviewer edits/merges or marks as Not a Duplicate with justification.
Readability, Accessibility, and Prohibited Content Checks
- Given project readability settings (e.g., Grades 6–10), When analysis runs, Then items outside the range are marked Warning: Readability and require reviewer acknowledgment to approve. - Given an item with images/math/rich text, When accessibility checks run, Then alt text is required for non-text content, math is screen-reader friendly, and color contrast meets WCAG 2.1 AA; any failure is Blocked: Accessibility and prevents approval. - Given item text, When prohibited content scanning runs, Then flagged terms/categories are highlighted; approval requires override with comment or content changes.
Confidence Scores with Transcript Evidence
- Given an item derived from transcript(s), When viewed, Then a confidence score (0.00–1.00) is displayed with at least two evidence snippets each showing a timestamp and transcript excerpt. - Given a reviewer clicks an evidence timestamp, When action occurs, Then the transcript viewer opens and auto-scrolls to the exact timecode. - Given a project minimum confidence threshold (e.g., 0.70), When an item’s score is below threshold, Then Approve is disabled until the reviewer selects Override and enters a reason captured in the audit log.
Role-Based Permissions Enforcement
- Given a Viewer role, When accessing the review screen, Then all edit/approve/regenerate/export/bulk controls are hidden or disabled. - Given an Editor role, When accessing, Then edit/regenerate/comment are enabled but Approve/Export remain disabled. - Given a Reviewer role, When accessing, Then edit/approve/bulk actions are enabled per policy. - Given any unauthorized action attempt, When performed, Then the system blocks the action, shows a 403-style notice, and records the attempt in the audit log.
Versioning and Audit Trail
- Given any saved edit, When the item is saved, Then a new immutable version is created recording user, timestamp, and a diff of changed fields. - Given an item with multiple versions, When a reviewer opens Version History, Then they can compare two versions side-by-side and revert to a prior version, creating a new head version. - Given an Approved item, When further edits are saved, Then its status changes to Needs Review and prior approvals remain in the history.
Bulk Actions and Export Gatekeeping
- Given a filtered selection of items, When Approve All is executed, Then only items passing all blocker checks are approved; items with warnings prompt for confirmation; a results report lists successes and reasons for skips. - Given selected items, When Bulk Retag or Regenerate Distractors runs, Then processing occurs asynchronously with a progress indicator and per-item success/failure log. - Given an Export to QTI/xAPI or direct LMS sync, When export runs, Then only Approved items are included; the package validates against the target schema, includes objective/chapter tags, and returns destination IDs; exporting with zero approved items shows a blocking message.

Standards Packager

Packages modules for SCORM 1.2/2004, xAPI, and Common Cartridge with manifest validation and auto-fixes for common errors. Includes readiness checks and one-click delivery to Canvas, Moodle, Blackboard, and Cornerstone—reducing upload failures and ensuring smooth LMS compatibility.

Requirements

SCORM Package Builder
"As an instructional designer, I want to export my ClipSpark module as a SCORM 1.2/2004 package so that I can deploy it to any LMS without manual packaging or compliance issues."
Description

Generate SCORM 1.2 and 2004-compliant packages from ClipSpark modules, including imsmanifest.xml, correctly referenced resources, and optional single-SCO or multi-SCO structures. Embed the ClipSpark player with captions (VTT), summaries as HTML assets, and one-click highlight clips as discrete SCOs or subresources. Provide configurable completion criteria (e.g., percentage watched, all highlights viewed), optional mastery score, and suspend data persistence. Output a standards-compliant ZIP ready for LMS import while preserving timestamps and transcript sync. Integrates with ClipSpark’s project model, allowing selection of which videos, captions, and highlights to include, and maps content metadata (title, description, duration) into manifest fields.

Acceptance Criteria
Generate SCORM 1.2 Single-SCO Package
Given a ClipSpark project with at least one video, associated VTT captions, and a summary is selected for export When the user selects "SCORM 1.2" and "Single-SCO" and clicks Build Package Then the output file is a ZIP containing imsmanifest.xml at the root And imsmanifest.xml conforms to SCORM 1.2 schema with zero validation errors And the manifest defines exactly one organization with one item and one corresponding resource And the resource's href launches the ClipSpark player entry file and all file references resolve And all selected VTT and summary HTML assets are included and referenced from the resource And the package imports successfully into a SCORM 1.2-compliant LMS without errors
Generate SCORM 2004 Multi-SCO Package
Given a project with highlight clips marked as discrete SCOs When the user selects "SCORM 2004 (4th Ed)" and "Multi-SCO" and clicks Build Package Then the ZIP contains imsmanifest.xml that validates against SCORM 2004 4th Ed XSDs with zero errors And each selected highlight is represented as a unique item and resource with a launchable href And the default organization enables choice and flow navigation across SCOs And the package imports and launches each SCO successfully in a SCORM 2004-compliant LMS
Runtime Player: Captions, Summaries, and Timestamp Sync
Given a built package is launched in a SCORM 1.2 or 2004 LMS When the ClipSpark player loads a selected video Then captions render from the referenced VTT with timing drift ≤ 0.5 seconds across the video And the summary content is accessible via an in-player HTML view without breaking SCORM communication And clicking a highlight navigates to the correct timestamp within ±0.3 seconds And no console errors occur during playback and caption loading
Configurable Completion and Mastery Criteria
Given completion is set to "Percentage watched = X%" (10 ≤ X ≤ 100) When a learner watches at least X% of the video duration Then SCORM 1.2 sets cmi.core.lesson_status to "completed" and SCORM 2004 sets cmi.completion_status to "completed" And if mastery score M is configured, raw score is reported and status is "passed"/"failed" per threshold (1.2: cmi.core.score.raw and lesson_status; 2004: cmi.score.raw and success_status) And if the learner watches < X%, completion status remains "incomplete"/"not attempted" as applicable And when completion is set to "All highlights viewed", completion occurs only after every highlight is viewed to end at least once
Suspend Data Persistence and Resume Playback
Given a learner exits mid-playback When the package stores state via the SCORM API on unload and at periodic intervals Then SCORM 1.2 uses cmi.suspend_data of length ≤ 4096 characters and SCORM 2004 uses cmi.suspend_data of length ≤ 64000 characters And on relaunch, playback resumes within 2 seconds of the last stored timestamp and previously viewed highlights remain marked And if suspend_data size would be exceeded, oldest non-essential entries are pruned without losing last position And no SCORM API errors are logged during store/restore
Highlights as Discrete SCOs or Subresources
Given the user chooses "Discrete SCOs" mode When the package is built and imported Then each highlight launches as an individual SCO and completion rollup marks the course complete when all highlight SCOs are completed And in "Subresources" mode, highlights are navigable within a single SCO and their view completion contributes to the single-SCO completion rule as configured And in both modes, highlight titles and durations are displayed and match project data
Project Selection and Metadata Mapping
Given the user selects a subset of videos, captions, and highlights from a ClipSpark project When the package is built Then only the selected assets are included in the ZIP and referenced by the manifest resources And manifest metadata maps project fields: title, description, and duration for each item/resource And missing optional fields do not block build; required fields cause a clear, actionable error message prior to build And all referenced files in imsmanifest.xml exist in the ZIP (0 broken references)
xAPI Package and Statement Mapping
"As a learning technologist, I want ClipSpark to produce xAPI packages with meaningful event mapping so that our LRS captures actionable analytics on learner interactions with videos and highlights."
Description

Create Tin Can/xAPI packages with tincan.xml, stable Activity IDs, and a launch wrapper that emits statements for key ClipSpark events (video started, paused, completed, highlight played, caption searched, timestamp jumped). Provide configurable LRS endpoint, credentials, and verb/object templates, with secure storage of secrets and SSL enforcement. Include offline queue and retry for intermittent connectivity and a test harness to preview emitted statements. Support basic result/completion semantics (e.g., completed when 90% watched) and optional extensions for timestamps and highlight IDs to retain ClipSpark context in downstream analytics.

Acceptance Criteria
xAPI Package Structure and Stable Activity IDs
Given a processed video and xAPI export is requested When the package is generated Then the ZIP contains a root-level tincan.xml, a launch HTML/JS wrapper, and all referenced assets Given the generated tincan.xml When validated against the Tin Can/xAPI XML schema Then validation passes with zero errors Given the same source video and metadata When packages are regenerated multiple times Then all Activity ID IRIs are stable and identical across builds Given an Activity in tincan.xml When resolving its launch URL Then it points to the included launch wrapper and loads without console errors Given the package is opened in a conformant player When launched Then the default Activity name and description match the ClipSpark source metadata
Launch Wrapper Emits Required Statements for Core Events
Given an authenticated learner and online connectivity When playback starts Then a Started/Initialized statement is sent within 2 seconds with actor, verb, object IRI, timestamp, and unique statementId Given playback is paused When the pause occurs Then a Paused statement is sent with current playback position in context/extensions Given playback reaches completion criteria When that occurs Then a Completed statement is sent once per learner/activity with result.completion=true Given a highlight clip is played When playback begins Then a statement is sent identifying the highlight via context.extensions.highlightId Given a caption search is performed When a search term is submitted Then a statement is sent with the search term and result count in extensions Given the learner jumps to a timestamp When the seek completes Then a statement is sent with from/to seconds in extensions Given any statement is emitted When inspected in the LRS Then actor, verb IRI, object IRI, timestamp (ISO 8601), and statementId (UUIDv4) are present and valid
Secure LRS Configuration and SSL Enforcement
Given an admin opens xAPI settings When setting the LRS endpoint Then only HTTPS endpoints are accepted; HTTP is rejected with a clear error Given endpoint, key, and secret are saved When persisted Then secrets are encrypted at rest and never exposed to client-side code or front-end logs Given a Test Connection action is invoked When valid credentials are provided Then a success response (2xx) and round-trip latency are displayed Given invalid credentials are provided When Test Connection is run Then a non-2xx response and actionable error are displayed without revealing secrets Given application logs are generated When xAPI operations occur Then credentials are redacted and endpoints partially masked
Offline Queueing and Reliable Retry
Given the device is offline When xAPI events occur Then statements are queued locally with original order preserved and unique statementIds assigned Given the app is closed or reloaded while offline When reopened Then the queued statements persist until delivery or explicit user/admin clear Given connectivity is restored When retry occurs Then queued statements are delivered in FIFO order with exponential backoff and jitter on failures up to a bounded max interval Given an LRS transient error (5xx or timeout) occurs When retrying Then delivery continues until success without creating duplicate statements in the LRS (idempotent by statementId) Given a permanent client error (4xx other than 409 conflict) occurs When detected Then the statement is marked undeliverable and surfaced in diagnostics with reason code
90% Completion and Result Semantics
Given watch progress is tracked by unique seconds viewed When the learner has cumulatively viewed at least 90% of the media Then a single Completed statement is emitted with result.completion=true and result.duration populated Given the learner watches less than 90% in a session When they exit Then no Completed statement is emitted and progress is persisted for future sessions Given the learner re-watches segments or scrubs backward/forward When counting progress Then only unique seconds contribute to the 90% threshold Given a Completed statement has been sent When the learner continues watching Then no additional Completed statements are sent for the same learner/activity
Test Harness Statement Preview and Validation
Given a developer opens the xAPI test harness When a sample session is simulated Then all configured events produce preview statements rendered as JSON Given preview statements are generated When validated Then each passes schema checks for xAPI 1.0.3 (actor, verb IRI, object IRI, ISO 8601 timestamp) and highlights any violations Given Send to LRS is triggered from the harness When valid LRS config exists Then statements are transmitted and the LRS HTTP status and response body are displayed Given credentials are present in configuration When previewing or transmitting Then secrets are redacted in the UI and network logs
Context Extensions for Timestamps and Highlight IDs
Given a timestamp jump or highlight playback occurs When a statement is sent Then context.extensions include IRIs configured for timestampSeconds and highlightId with correct values Given extensions are enabled in settings When statements are emitted Then extension IRIs are absolute, HTTPS, and stable across sessions Given extensions are disabled in settings When events occur Then statements omit those extensions while remaining valid xAPI
Common Cartridge Export
"As an educator, I want to export my ClipSpark content as a Common Cartridge so that I can quickly add it to different LMS platforms without reformatting."
Description

Export modules as IMS Common Cartridge (1.1/1.2/1.3) packages with a compliant manifest, organizing videos, summaries, and highlight clips as web content items and pages. Convert ClipSpark summaries into HTML pages, include caption files, thumbnail assets, and optional external LTI links to the hosted ClipSpark player when needed. Preserve ordering and module structure, generate resource identifiers, and ensure all hrefs resolve. Produce a ZIP ready for import into Canvas, Moodle, Blackboard, and other CC-compatible LMSs.

Acceptance Criteria
Versioned IMS CC Export and Schema Validation
Given a project containing at least one module When the user exports as "IMS Common Cartridge 1.1" Then imsmanifest.xml validates against the IMS CC 1.1 schema with zero errors Given the same project When the user exports as "IMS Common Cartridge 1.2" Then imsmanifest.xml validates against the IMS CC 1.2 schema with zero errors Given the same project When the user exports as "IMS Common Cartridge 1.3" Then imsmanifest.xml validates against the IMS CC 1.3 schema with zero errors And the package contains only spec-compliant files referenced by the manifest (no hidden/system files)
Module Hierarchy and Ordering Preservation
Given a module with nested sections and items ordered A→B→C When exporting to IMS CC Then the <organizations>/<organization>/<item> tree mirrors the nesting and preserves the order A→B→C And each <item> has a unique @identifier and an @identifierref that points to an existing <resource> And the total number of <item> elements equals the number of exportable items in the source module And item titles in the manifest match the ClipSpark item titles
Summary-to-HTML Conversion and Page Resources
Given a ClipSpark summary for a video When exporting to IMS CC Then a UTF-8 HTML file is generated that contains the summary title and body content And the HTML is referenced by a <resource> of type webcontent with a unique @identifier and correct href And all assets referenced by the HTML (images, CSS) are included and resolve via relative paths And an <item> is created that points to the summary page with the correct title
Media and Highlight Clip Pages with Captions and Thumbnails
Given a video with associated caption files and a thumbnail When exporting to IMS CC Then a web page (HTML) is generated that embeds or links the video and includes caption tracks And all caption files (.vtt or .srt) are included in the package and referenced with correct relative paths And the thumbnail is included and referenced as the poster image for the media element And for each highlight clip, a separate page or section is generated with the correct title and time-bound playback (e.g., URL time fragment) And the corresponding <resource> lists all included files under <file> entries
Optional LTI Link to ClipSpark Player
Given external playback is enabled for a media item When exporting to IMS CC Then the package includes a cartridge_basiclti_link resource that launches the hosted ClipSpark player via the configured launch URL And the <item> for this media points to the LTI resource instead of a local HTML page And no local media file is included for that item unless the user explicitly selected both local page and LTI And required LTI metadata (title, description, launch_url) is present and passes Common Cartridge LTI validation
ZIP Packaging, Resource Identifiers, and Href Integrity
Given an export is generated When the ZIP is created Then the root contains imsmanifest.xml and the resource directory structure exactly as referenced by the manifest And every <resource> @identifier is unique and matches the pattern res-<uuid> And 100% of hrefs referenced by <resource> and packaged HTML pages resolve to existing files when the ZIP is extracted And the ZIP excludes OS-specific artifacts (e.g., __MACOSX, .DS_Store) and uses file paths of 255 characters or fewer
LMS Import Success (Canvas, Moodle, Blackboard)
Given a generated export ZIP When importing into Canvas, Moodle, and Blackboard test instances Then each LMS completes the import with zero errors And the counts of modules/pages/items created in the LMS match the exported source counts And opening a media item renders the page, plays the video, and loads captions successfully And highlight clips appear as separate items/pages with correct titles and working links
Manifest Validator and Auto-Fix Engine
"As a content developer, I want automated validation and auto-fixes during packaging so that I can avoid tedious troubleshooting and reduce LMS upload failures."
Description

Validate SCORM (1.2/2004), xAPI, and Common Cartridge manifests and package structures against schemas and best practices. Detect common issues (missing or duplicate identifiers, broken hrefs, incorrect resource types, sequencing defaults, metadata omissions) and automatically correct safe-to-fix problems. Provide a human-readable validation report with error/warning levels, before/after diffs for auto-fixes, and links back to source content to resolve remaining issues. Run validation pre- and post-packaging to minimize LMS upload failures.

Acceptance Criteria
Cross-Standard Manifest Schema Validation
- Detect and auto-identify standard/version (SCORM 1.2/2004, Common Cartridge, xAPI Tin Can or cmi5) from manifest root and namespaces. - Validate manifest against the appropriate schema/constraints; report zero errors for compliant files. - For invalid manifests, report each violation with severity=error, code, message, file path, and line/column. - Flag mixed or conflicting manifests (e.g., imsmanifest.xml with tincan.xml) as errors with remediation guidance. - Exit status = "Valid" when no errors; = "Invalid" when any errors.
Auto-Fix Identifiers and Reference Consistency
- Generate unique, deterministic identifiers for missing/duplicate IDs and update all internal references accordingly. - Preserve externally referenced IDs marked as external; do not auto-modify. - Log each applied fix with before/after diff and affected files count. - If a safe fix cannot be computed deterministically, do not modify; leave as error.
Resource HREF Integrity and Safe Path Corrections
- Resolve every href to an existing file within the package; prevent directory traversal outside the package root. - Auto-correct case-only filename mismatches and missing './' prefixes when the target exists; update all references. - Report unresolved hrefs as errors with a list of missing targets and referring nodes; no destructive fixes applied. - External http/https links are allowed but flagged as warnings unless allowExternalLinks=true.
SCORM Sequencing Defaults and Resource Type Validation
- Insert default sequencing elements for SCORM 2004 (e.g., controlMode choice=true, flow=true) when omitted; log diffs for each insertion. - Validate resource scormType and launch attributes; reclassify asset→sco only when a definitive launchable entry point is detected. - For SCORM 1.2, require at least one launchable SCO when organizations exist; otherwise raise an error with offending org/item references. - Never apply auto-fixes that change launch behavior without deterministic detection; such cases are warnings or errors only.
Metadata Completeness and Normalization
- Ensure required metadata (e.g., title, language) exists for organizations/items/resources; auto-fill from package-level defaults when safe; mark as warnings. - Validate LOM/DC elements per standard; report omissions as warnings and do not fabricate content-specific values. - Normalize xml:base and relative paths to a canonical form; log each normalization in the report. - Do not overwrite existing metadata values; only fill when absent.
Validation Report, Diffs, and Source Linking
- Produce both an HTML report and a JSON summary for each validation run. - Each issue entry includes severity (error/warning/info), code, message, file path, line/column, and a deep link to open the source location in ClipSpark. - Include a unified before/after diff snippet and rationale for every auto-fix applied. - Enable filtering by severity, standard, file, and fix status in the report UI; filters do not alter stored results.
Pre- and Post-Packaging Validation Gates
- Run validation automatically before packaging; block packaging when any errors exist; warnings do not block. - Re-run validation on the final packaged ZIP; no new errors may be introduced post-packaging; otherwise mark packaging as failed. - If auto-fixes were applied pre-packaging, package must be built from the fixed sources; no new auto-fixes are applied post-packaging. - Emit pass/fail status and a readiness summary via API and display the same in the UI.
One-Click LMS Delivery
"As a program manager, I want one-click delivery of packages from ClipSpark to our LMS so that I can publish updates quickly without manual uploads."
Description

Enable direct delivery of packaged content to Canvas, Moodle, Blackboard, and Cornerstone via secure API integrations. Support OAuth2/API key authorization, course and module selection, create vs. update flows, and progress tracking for imports. Provide delivery logs, error surfacing with remediation tips, and the ability to re-deploy or roll back to prior versions. Store credentials securely, respect tenant scoping, and provide audit trails. This streamlines distribution and reduces manual LMS import steps.

Acceptance Criteria
Secure LMS Authentication & Credential Management
- Given a tenant admin initiates an LMS connection, When authorizing via OAuth2 or API key as supported by the LMS, Then credentials are stored encrypted at rest with KMS-managed keys and scoped strictly to that tenant. - Given a valid connection exists, When a user from another tenant attempts to access it, Then access is denied with 403 and the attempt is recorded in the audit trail. - Given an access token is expired, When a delivery is started, Then the token is refreshed automatically; If refresh fails, Then the user is prompted to re-authenticate and the delivery is paused without data loss. - Given a user selects Disconnect/Revoke, When revocation completes, Then tokens and secrets are purged within 5 minutes and subsequent API calls fail until reconnected. - Given system and delivery logs are generated, When reviewing logs, Then no secrets (tokens, client secrets, API keys) are present and sensitive fields are redacted. - Given rate limits or auth errors occur, When retries are attempted, Then exponential backoff with a maximum of 3 retries is applied and surfaced to the user with an actionable message.
Target Course/Module Selection UI
- Given a valid LMS connection, When the user opens "Deliver to LMS", Then the system lists accessible courses with pagination and search, returning first results within 3 seconds for datasets up to 5,000 courses. - Given a course is selected, When loading destinations, Then valid placements (e.g., modules, content areas, assignments) for that LMS are displayed with display names and underlying LMS IDs. - Given the user lacks required LMS permissions, When fetching courses or destinations, Then the UI shows a clear error with remediation tips and a link to required scopes/roles. - Given filters and search terms are applied, When results are shown, Then only matching courses/destinations are returned and counts reflect the filter. - Given a target is confirmed, When proceeding to delivery, Then the selected course and destination identifiers are persisted with the delivery record.
Create vs Update Delivery Flow
- Given preflight checks pass (manifest validity, file size limits, LMS capability), When the target contains no prior package with the same logical identifier, Then a new content item/module is created with the provided name and version tag. - Given a matching prior package exists, When the user selects Update, Then the content is updated in place preserving LMS item IDs and links, and the version is incremented. - Given a matching prior package exists, When the user selects Create New, Then a new item is created alongside the existing one with a distinct title/version label. - Given a content lock or conflict occurs, When attempting update, Then the user is presented options to Retry, Duplicate as New, or Cancel, and the chosen action is recorded. - Given delivery completes, When writing the delivery record, Then the action (Create/Update), LMS object IDs, version, actor, and timestamps are stored in the audit trail.
Import Progress Tracking
- Given a delivery has started, When the LMS processes the import asynchronously, Then a progress indicator displays 0–100% with status updates at least every 5 seconds until a terminal state (Success/Failed/Cancelled). - Given network interruption occurs during import, When connectivity resumes, Then progress polling resumes without triggering duplicate imports; If no updates are received for 30 minutes, Then the job is marked Timed Out with a Retry option. - Given multiple deliveries run concurrently, When viewing the dashboard, Then each delivery shows independent, realtime progress and supports cancel/pause if the LMS API supports those actions. - Given the LMS returns a job ID, When polling, Then requests include the job ID and handle 429/5xx with backoff, surfacing a clear message on sustained failures.
Delivery Logs & Actionable Error Surfacing
- Given any delivery is executed, When viewing delivery logs, Then time-stamped events (preflight, upload, import, finalize) are shown with request method, masked endpoint, response codes, LMS job IDs, and messages. - Given an error occurs, When categorizing the error, Then it is labeled (Auth, Permission, Manifest, Quota, Size, Rate Limit, Unknown) and the UI shows a human-readable message plus a remediation tip with a docs link. - Given a support request is needed, When copying diagnostic data, Then a request ID and correlation IDs can be copied to clipboard without exposing secrets. - Given a user exports logs, When export is triggered, Then a JSON or CSV file downloads within 10 seconds containing the full event trail for that delivery.
Redeploy and Rollback to Prior Versions
- Given prior successful deliveries exist, When the user selects Redeploy for a past version, Then the same package artifact is delivered to the chosen target without repackaging and the delivery is linked to the original in the audit trail. - Given a recent update caused issues, When the user selects Rollback, Then the LMS is reverted to a selected prior version; If native rollback is not supported, Then the system re-deploys the prior artifact as an update and communicates this behavior. - Given rollback completes, When viewing records, Then the delivery shows action=Rollback with previous and current version IDs, actor, timestamps, and final status. - Given redeploy/rollback fails mid-process, When error handling triggers, Then a clear failure reason and remediation tip are surfaced with the option to retry.
Audit Trails & Tenant Scoping
- Given any delivery-related action occurs, When viewing the audit trail, Then entries include actor, tenant, LMS type, course/destination IDs, action (Create/Update/Redeploy/Rollback), status, version, and timestamps, and entries are immutable. - Given a tenant admin reviews records, When applying filters, Then results can be filtered by date range, LMS, course, user, status, and version, and only the admin’s tenant data is visible. - Given a large history exists, When exporting audit data, Then CSV export completes within 30 seconds for up to 100,000 records, with pagination cues for larger datasets.
Preflight Readiness Checks
"As a course builder, I want a readiness checklist before export so that I can fix issues early and avoid failed packages or LMS imports."
Description

Run preflight checks before packaging and delivery to ensure all prerequisites are met: presence of video sources, synced captions, summary generation, highlight clip availability, valid metadata, reasonable file sizes, and selected standards options (version, completion criteria). Simulate launch to verify player assets resolve and manifests can be generated. Present a pass/fail checklist with actionable fixes and estimated packaging time to increase first-pass success rates.

Acceptance Criteria
Required Inputs Presence Check
Given a project is opened in Standards Packager When Preflight Readiness Checks are run Then the system verifies presence of at least one video source file And verifies at least one synced captions file per video or captions are explicitly marked "Not required" And verifies a generated summary exists And verifies at least one highlight clip is available or highlight generation is intentionally skipped And verifies required metadata fields exist (title, language, duration) And verifies a standards type and version are selected And marks each prerequisite as Pass, Warn, or Fail And the overall prerequisite check status is Pass only if all critical items Pass
Captions Sync and Format Integrity
Given at least one captions file is attached per video When Preflight Readiness Checks validate captions Then the captions file must be UTF-8 encoded and one of SRT or WebVTT And all caption cues have strictly increasing start/end timestamps within video duration And cue duration is between 0.5s and 15s inclusive And the median alignment drift between speech and captions is <= 500 ms and the 95th percentile drift is <= 1000 ms And a valid language code (BCP-47) is present And the check marks Pass only if all conditions are met; otherwise marks Fail with specific reasons
Standards-Specific Metadata and Configuration Validation
Given the user has selected a packaging standard (SCORM 1.2/2004, xAPI, or Common Cartridge) When Preflight Readiness Checks run metadata and configuration validation Then SCORM requires a course title (1–140 chars), an identifier matching ^[A-Za-z0-9._-]{1,64}$, a defined launch file path, and for SCORM 2004 a mastery_score between 0 and 100 if mastery-based completion is selected And xAPI requires an Activity ID that is a valid IRI/URI, an activity name (1–140 chars), and a launch URL when using a launch protocol And Common Cartridge requires unique item identifiers and a valid organization title in imsmanifest And cross-standard fields title, description (<= 2000 chars), primary language (BCP-47), and author/organization are present And incompatible option combinations are rejected with an explanation And the check marks Pass only if the selected standard’s full set passes
File Size and Duration Sanity Thresholds
Given all referenced media assets are available When Preflight Readiness Checks evaluate sizes and durations Then each video file size must be <= 1.5 GB (configurable), with a Warning if > 500 MB And total package payload estimate must be <= 2.0 GB (configurable) And reported video duration matches probed media duration within ±1 second And missing or corrupt media streams cause Fail with the asset path listed And the check marks Pass only if all thresholds are met without Fail
Simulated Launch: Assets Resolve and Manifests Validate
Given a selected standard and target LMS profile When the user runs Simulate Launch Then the system generates manifest(s) and validates against the corresponding schema without errors And all referenced player assets and media resolve via their manifest-declared paths And HTTP-accessed resources return 200 within 5 seconds per request during simulation, or local file handles are readable And cross-origin and content-type headers required by the player runtime are valid for the target LMS profile And the simulation produces a log with zero errors for a Pass result
Actionable Fixes and Auto-Fix Workflow
Given one or more checks have Fail or Warn outcomes with known auto-fixes When the user selects Auto-fix all or an individual Fix action Then the system applies the fix atomically, lists the changed items, and timestamps the change And upon completion, the Preflight Readiness Checks are automatically re-run And all issues marked Fixable transition to Pass or Warn-resolved on the next run And any items that cannot be auto-fixed remain with clear instructions for manual resolution
Readiness Checklist and Packaging Time Estimate
Given Preflight Readiness Checks have completed When the results are presented Then a checklist displays each check with Pass/Warn/Fail status and a link to details or fix And the Ready to Package call-to-action is enabled only when all critical checks are Pass and no Fail remains And an estimated packaging time is displayed in seconds, computed from asset count and size And the actual packaging time recorded differs from the estimate by no more than ±20% for successful runs up to 30 minutes

Adaptive Chapters

Generates micro, standard, and deep-dive chapter variants from the same source, targeting specific runtimes and audience expertise. Preserves learning objectives and recalibrates quiz difficulty accordingly—letting teams tailor content for different channels without re-editing.

Requirements

Chapter Variant Generation Engine
"As a content producer, I want the system to automatically generate micro, standard, and deep-dive chapter variants from a single recording so that I can publish tailored cuts without re-editing."
Description

Generate micro (30–90s), standard (3–7 min), and deep-dive (10–20+ min) chapter variants from a single source video by combining ASR transcripts, semantic topic segmentation, and scene-change detection. Maintain exact timestamp alignment, titles, and concise summaries per chapter, with deterministic, reproducible outputs via model versioning and seed control. Provide configurable constraints for runtime windows, topic coverage, and minimum context continuity. Output a structured payload for each variant (start/end timecodes, title, synopsis, key takeaways, objective tags) that integrates with ClipSpark’s media store, caption pipeline (SRT/VTT), and downstream export services.

Acceptance Criteria
Variant Runtime Windows Are Enforced
Given runtime_windows configured as micro=30–90s, standard=180–420s, deep_dive=600–1200s When the engine generates micro, standard, and deep-dive variants from a single source video Then 100% of micro chapters have durations between 30.0s and 90.0s inclusive And 100% of standard chapters have durations between 180.0s and 420.0s inclusive And 100% of deep-dive chapters have durations between 600.0s and 1200.0s inclusive (or ≥600.0s when the deep_dive max is configured as open-ended) And there are no overlaps between consecutive chapters and no gaps greater than 0.5s within any variant And the sum of chapter durations per variant is within ±1.0s of the variant’s covered source range
Deterministic Output via Model Versioning and Seed
Given the same source video, identical ASR transcript, model_version=V, and random_seed=S When the engine is executed three times Then the generated variants’ chapter boundaries, titles, synopses, key_takeaways, objective_tags, and timecodes are identical across all runs And the payload includes model_version=V and random_seed=S When only random_seed changes to S2 Then at least one chapter boundary or metadata field differs while all configured constraints remain satisfied When only model_version changes to V2 Then the payload includes model_version=V2 and outputs still satisfy all configured constraints
Timestamp Alignment and Caption Sync Integrity
Given word-level ASR tokens with timecodes and detected scene-change events When chapter start and end timecodes are assigned and SRT/VTT are generated per variant Then each chapter start and end timecode aligns to an ASR token boundary within ±50 ms And no caption starts before its chapter start or ends after its chapter end And there are no caption overlaps across consecutive chapters within the same variant And WebVTT and SubRip files validate successfully with no format errors And the maximum caption drift within any chapter is ≤ 100 ms at chapter end
Structured Payload Validates and Integrates
Given the generated payloads for micro, standard, and deep-dive variants When validating against the ClipSpark ChapterVariant schema Then every chapter includes start_timecode (HH:MM:SS.mmm), end_timecode (HH:MM:SS.mmm), title (non-empty), synopsis (1–500 chars), key_takeaways (1–5 items), and objective_tags (≥1 tag) And chapter arrays are ordered by start_timecode ascending with strictly increasing start times When submitting the payload to the Media Store, Caption Pipeline, and registered Export Services Then each service responds with HTTP 200/Success and creates the expected artifacts (chapter records, SRT/VTT files, and export manifests)
Topic Coverage and Context Continuity Constraints
Given semantic topic segments and scene-change detections and constraints topic_coverage=required and min_context_continuity=5.0s When generating all variants Then 100% of top-level semantic topics detected in the source are represented in at least one chapter across the variants And within the standard variant, at least 90% of chapter boundaries fall within ±1.0s of either a semantic topic boundary or a scene-change event And no chapter boundary is placed within 0.5s of the middle of an ASR word And at least 95% of chapters do not span more than two top-level semantic topics
Graceful Handling of Unfulfillable Constraints
Given a source video that cannot satisfy one or more configured constraints When requesting generation of all variants Then the engine flags the unsatisfiable variant(s) with a machine-readable list of violated constraints and does not emit partial chapters for those variants And satisfiable variants are still generated when allow_partial=true And the entire request fails with an explanatory error when allow_partial=false
Runtime Targeting & Coverage Constraints
"As a video editor, I want to specify target runtimes and coverage constraints per variant so that outputs meet channel requirements without losing essential context."
Description

Enable per-variant target runtimes with hard/soft bounds and topic coverage constraints. Optimize chapter selection to hit the runtime target within ±10% while preserving narrative flow, speaker continuity, and prerequisite context. Provide a constraint solver that surfaces infeasibility and offers trade-off suggestions (e.g., merge adjacent segments, relax coverage on low-priority topics). Include preset profiles (e.g., 60s micro, 5-min standard, 15-min deep-dive) and allow organization-level defaults. Expose controls in UI and API, and record chosen constraints in variant metadata for auditability.

Acceptance Criteria
Per-Variant Target Runtime with Hard/Soft Bounds (UI & API)
Given a source video and a new Adaptive Chapters variant When the user sets a target runtime and selects a bound type of Hard or Soft via UI or API Then the solver produces a chapter set whose total duration is within ±10% of the target when feasible And for Hard bounds, no solution outside ±10% is produced or auto-saved And for Soft bounds, if no ±10% solution exists, the solver returns a best-fit candidate, a warning, and trade-off options without auto-publishing
Topic Coverage Constraints with Priorities and Prerequisites
Given topic constraints specifying required topics, optional topics with minimum coverage, topic priorities, and a prerequisite map When the solver selects chapters Then all required topics and their prerequisite context are included And optional topics meet their minimum coverage unless infeasible, in which case only the lowest-priority optional topics are relaxed And any relaxation is reported with amounts and affected topics
Narrative Flow and Speaker Continuity Preservation
Given transcript-aligned segments with sentence and speaker boundaries When the solver trims or merges segments to meet runtime Then no selected clip starts or ends mid-sentence And no single speaker turn is split across chapter boundaries And adjacent segments are merged when necessary to maintain continuity without violating constraints
Infeasibility Detection with Actionable Trade-offs
Given any set of runtime bounds and coverage constraints When the solver determines the constraints are infeasible Then the API responds with 422 and a payload listing the minimal conflicting constraints and reasons And the payload includes trade-off suggestions that can be applied with one click: merge adjacent segments, relax coverage on lowest-priority topics with specific percentages, or adjust the target runtime within allowed bounds And the UI surfaces the same suggestions with clear labels and recompute actions
Preset Profiles Apply Correct Constraints
Given the preset profiles "60s Micro", "5-min Standard", and "15-min Deep-dive" When a user applies a preset via UI or API to create a variant Then the variant initializes with the profile's target runtime, default bound type, and default topic coverage settings And the solver attempts a solution meeting the profile runtime within ±10% or returns infeasibility with trade-off suggestions per policy
Organization-Level Defaults and Per-Variant Overrides
Given an organization-level default profile and constraint template set by an admin When a new project or variant is created under that organization Then those defaults auto-apply to the variant And users with edit permissions can override constraints per project/variant via UI or API And all applications and overrides are logged with user, timestamp, and values
Variant Metadata Auditability (UI & API)
Given a generated variant When a user retrieves its metadata via UI or API Then the metadata contains target runtime, bound type, topic constraints, solver version, feasibility status, final duration, applied trade-offs, and audit trail (user and timestamps) And metadata is immutable after publish and versioned on subsequent re-runs And metadata is exportable as JSON for compliance
Learning Objectives Preservation
"As an instructional designer, I want chapter variants to preserve and evidence learning objectives so that even shorter versions achieve the intended learning outcomes."
Description

Capture learning objectives at the source asset level and map them to transcript spans using embeddings and keyword alignment. Ensure that every generated variant maintains coverage of required objectives; flag uncovered objectives and suggest candidate segments to include. Produce an objective coverage report per variant (covered, partially covered, uncovered) and embed objective tags into chapter metadata. Provide guardrails that prevent publishing variants marked as missing required objectives unless explicitly overridden with justification.

Acceptance Criteria
Source Objectives Capture and Mapping to Transcript Spans
Given a source asset with one or more learning objectives entered via UI or API, When the asset is processed, Then each objective is evaluated against the full transcript using hybrid embeddings and keyword alignment, And each objective is mapped to one or more transcript spans with start/end timestamps in seconds, And each mapping includes a confidence score between 0 and 1, And objectives with no qualifying span (confidence < 0.6 or span < 5s) are marked Unmapped, And processing completes within 10 minutes for a 2-hour asset on standard tier infrastructure.
Variant Coverage Evaluation and Status Assignment
Given micro, standard, and deep-dive variants have selected chapters for the asset, When objective coverage is computed for a variant, Then an objective is Covered if the variant includes at least one mapped span with ≥80% of that span’s duration contained within chapters, And an objective is Partially Covered if cumulative overlap across included chapters is ≥20% and <80%, And an objective is Uncovered otherwise, And the variant receives an Overall Status of Missing Required Objectives if any required objective is not Covered, And the UI displays the per-objective status counts (Covered, Partially Covered, Uncovered) and Overall Status.
Uncovered Objective Flagging and Candidate Segment Suggestions
Given a variant contains Partially Covered or Uncovered objectives, When the review screen is opened for that variant, Then the system lists each such objective with the top 3 candidate transcript segments ranked by confidence, And each candidate includes start/end timestamps, estimated coverage %, and the source rationale (embedding/keyword matches), And the user can add a candidate as a new chapter or extend an existing chapter with one click, And coverage is recomputed within 5 seconds after the change, And updated statuses are reflected immediately in the UI.
Objective Coverage Report Generation and Export
Given coverage has been computed for a variant, When the user requests a coverage report, Then a report is generated containing 100% of source objectives with fields: objective_id, title, required_flag, status (Covered/Partially/Uncovered), mapped_confidence_max, covered_chapter_ids, covered_timestamps, And the report includes asset_id, variant_id, processing_version, and generated_at timestamp (UTC), And the report is downloadable as JSON and CSV from the UI and retrievable via API, And for assets with up to 200 objectives, the report is produced within 3 seconds and is ≤5 MB.
Objective Tags Embedded in Chapter Metadata
Given chapters are generated for any variant, When chapter metadata is saved or exported, Then each chapter includes an objectives array with objective_id, role (primary|secondary), and covered_span timestamps, And objective tags persist in the variant’s JSON manifest and are embedded in timecoded caption/marker exports where supported (e.g., WebVTT notes), And reloading the project preserves these tags without loss or duplication.
Publish Guardrails, Override, and Audit Trail
Given a user attempts to publish a variant whose Overall Status is Missing Required Objectives, When the publish action is initiated, Then the system blocks publishing and displays the list of unmet required objectives with statuses, And an Override with Justification control is presented, And publishing remains blocked until a justification of at least 20 characters is provided and the user confirms override, And upon override, the publish succeeds and an audit record is stored with user_id, timestamp (UTC), justification text, and the list of unmet objectives, And the audit record is visible in the activity log and retrievable via API.
Audience Expertise Profiling
"As a program manager, I want to tailor chapter language and depth to audience expertise so that each variant resonates with its intended viewers."
Description

Support audience profiles (novice, intermediate, expert) that modulate chapter titling, synopsis tone, and depth cues without altering factual content. For novice variants, add scaffolding and definitions; for expert variants, compress background and emphasize advanced insights. Apply controlled vocabulary and style guides at the org level. Include a readability target per profile and validate outputs against it, with automatic rewrites when out of bounds. Store the selected profile in variant metadata for analytics and routing.

Acceptance Criteria
Novice Profile: Readability and Scaffolding Enforcement
Given an organization has readability targets configured (Novice: Flesch-Kincaid Grade Level <= 8) and a controlled glossary of domain terms, When chapters (micro, standard, deep-dive) are generated with audience_profile = novice, Then each chapter synopsis has FKGL <= 8, And each chapter defines any non-common domain term on first mention with a parenthetical or footnote definition, And no sentence exceeds 25 words, And at least one example or analogy sentence is present per chapter, And zero validation violations are reported.
Expert Profile: Background Compression and Advanced Emphasis
Given a processed source transcript and audience_profile = expert, When chapters (micro, standard, deep-dive) are generated, Then the proportion of background/context sentences per chapter synopsis is <= 20%, And at least two advanced insight cues (e.g., implications, trade-offs, edge cases) are present per chapter, And FKGL >= 13, And definitions or glossary scaffolding are omitted, And the synopsis word count is <= 70% of the intermediate variant for the same chapter, And zero validation violations are reported.
Intermediate Profile: Balanced Tone and Depth Cues
Given audience_profile = intermediate, When chapters are generated, Then FKGL is between 9 and 12 inclusive, And each chapter includes 1-2 background/context sentences and at least 1 analytical/insight sentence, And titles include necessary technical terms but avoid unexplained acronyms (100% of acronyms expanded on first use), And the synopsis word count is between 70% and 120% of the standard benchmark set by org style, And zero validation violations are reported.
Org-Level Style Guide and Controlled Vocabulary Application
Given an org-level style guide and controlled vocabulary map (including required terms, banned terms, title casing rules), When any audience profile variant is generated, Then 100% of required term replacements are applied, And 0 occurrences of banned terms are present, And chapter titles conform to the configured casing rule, And punctuation and number formatting rules pass automated lint checks with 0 errors, And a style_compliance report is attached to the artifact.
Readability Validation and Auto-Rewrite Loop
Given readability targets per audience profile are configured, When a generated title or synopsis falls outside the profile's target, Then the system automatically rewrites up to 3 iterations, And stops early when the target is met, And if still out-of-bounds after 3 iterations, the variant is flagged status = "Needs Review" with the offending metric and delta recorded, And all iterations are logged with before/after metrics.
Variant Metadata: Profile, Readability Target, and Audit Trail
Given a chapter variant is created for any audience profile, When the variant is saved or published, Then the metadata includes audience_profile, readability_metric (name and score), readability_target, style_guide_version, vocabulary_version, generation_timestamp, and validation_results, And this metadata is retrievable via API and UI, And analytics can filter and aggregate by audience_profile, And routing rules can target variants by audience_profile with 100% match accuracy.
Factual Content Invariance Across Profiles
Given novice, intermediate, and expert variants are generated from the same source, When comparing cross-profile chapter synopses and titles, Then named entities, numeric values, temporal order, and core claims match exactly across profiles (0 discrepancies by automated NER/number/order checks), And no factual statements are added or removed, And any differences are limited to tone, depth cues, and compression, And a fact_consistency report shows Pass for all chapters.
Quiz Difficulty Recalibration
"As an educator, I want quiz difficulty to automatically recalibrate to each variant and audience level so that assessments remain fair and aligned."
Description

Recalibrate assessment items linked to chapters based on variant length, objective coverage, and selected audience profile. Adjust difficulty using item templates mapped to Bloom’s levels, regenerate distractors for plausibility at the chosen expertise level, and right-size the number of questions per variant. Ensure each item references only content present in the variant and passes alignment checks to learning objectives. Provide a review workflow with item stats (estimated difficulty, discrimination proxies) and maintain version history.

Acceptance Criteria
Difficulty Mapping by Variant and Audience
Given a chapter variant (micro | standard | deep-dive) and a selected audience profile (novice | intermediate | expert) When quiz items are recalibrated Then each item is assigned a Bloom’s level from the audience-specific template And the distribution of Bloom’s levels matches the variant profile within ±10%: - Micro/Novice: ≥70% Remember/Understand, ≤30% Apply - Standard/Intermediate: ≥50% Apply/Analyze, ≤50% Remember/Understand - Deep-dive/Expert: ≥60% Analyze/Evaluate/Create And ≥95% of items comply with the target distribution, with non-compliant items flagged with rationale
Plausible Distractor Generation by Expertise Level
Given a multiple-choice item template and a selected audience profile When distractors are regenerated Then each item contains exactly 3 distractors plus 1 correct option And no distractor is a duplicate or near-duplicate of another (normalized Levenshtein similarity < 0.85) And no distractor contains the exact correct answer string or trivial negation thereof And distractor readability meets audience targets (Novice ≤ Grade 8, Intermediate ≤ Grade 10, Expert ≤ Grade 12 by Flesch-Kincaid) And each distractor includes an internal rationale referencing a variant transcript span ID and is marked false_in_context by the validator And the automated plausibility score for each distractor is ≥ 0.70; items with any distractor < 0.70 are auto-regenerated up to 2 times and then flagged for review
Question Count Right-Sizing by Variant Length and Objective Coverage
Given a generated chapter variant with runtime and the set of learning objectives present in that variant When quiz items are recalibrated Then the total number of items is set by runtime bucket: - Micro (≤5 min): 3–4 items - Standard (6–20 min): 6–8 items - Deep-dive (>20 min): 10–12 items And each objective present in the variant has at least 1 item mapped And if item capacity exceeds the count of objectives, objectives marked higher priority receive ≥1 additional item before lower priority objectives And any attempt to publish with fewer items than objectives prompts a prioritization/merge action and blocks publish until resolved
Variant-Only Content Referencing with Timestamps
Given a set of recalibrated items for a variant When items are generated or regenerated Then 100% of items include at least one evidence link to a timestamp range within the variant transcript And no item references a transcript span or timestamp outside the variant; if detected, the item is blocked from approval with an error message And evidence links are clickable and open playback at the start time within ±1 second And items without valid evidence links cannot be approved or published
Alignment to Learning Objectives
Given defined learning objectives and their inclusion within a variant When items are recalibrated Then each item is mapped to exactly 1 primary objective and optionally 1 secondary objective And coverage across objectives included in the variant is 100% (no objective without ≥1 mapped item), unless the number of objectives exceeds the allowed item count; in that case, the system requires objective prioritization before publish And each item’s alignment score to its primary objective is ≥ 0.75; items below threshold are auto-regenerated up to 2 times and then flagged for review And no item is orphaned (0 mapped objectives) at publish time
Reviewer Workflow with Item Stats and Actions
Given a reviewer opens the recalibrated item set for a variant When the review panel loads Then each item displays: estimated difficulty (0–1), discrimination proxy (0–1), Bloom’s level, objective mapping, evidence timestamps, current version number, and change log summary And the reviewer can Approve, Edit, or Reject each item; actions persist immediately with user and timestamp And editing an item creates a new version (version increments by +0.0.1) while preserving the stable item ID And the reviewer can bulk-approve items that meet all automated checks And exporting the current item set to CSV and JSON includes all displayed stats and mappings
Version History and Rollback Controls
Given items have undergone edits or regenerations When a user views version history for an item Then the system lists at least the last 20 immutable versions with diffs for stem, options, feedback, Bloom’s level, objective mapping, and evidence spans And selecting Restore on a prior version creates a new head version cloned from that prior content; historic versions remain unchanged And quiz-level version increments when any item changes, with a semantic version note describing the change set And all version operations (create, restore, publish) are audit-logged with user, timestamp, and reason
Channel Export Templates & One-Click Publishing
"As a marketer, I want one-click exports of each variant to my target channels with correct metadata and captions so that I can publish quickly and consistently."
Description

Offer prebuilt export templates for major channels (YouTube chapters, LMS modules, show notes for podcasts, TikTok descriptions) that transform variant metadata into channel-specific formats. One-click export packages include trimmed media references or edit-decision lists (EDLs), caption slices (SRT/VTT), thumbnails, and JSON metadata. Provide API/webhook integrations for automated handoff to MAM/DAM and social schedulers, with per-channel rate limiting, retries, and delivery receipts logged for observability.

Acceptance Criteria
One-Click Export: YouTube Chapters Package
Given a processed recording with Adaptive Chapters variants (micro, standard, deep-dive) and a connected YouTube channel template When the user selects a variant and clicks Publish > YouTube Chapters Then the system generates a package ZIP named {videoId}_{variant}_youtube.zip containing: - chapters.txt with lines in HH:MM:SS Title format, starting at 00:00 and strictly ascending start times - captions/ containing per-chapter .srt and .vtt files time-bounded to each chapter - thumbnails/ containing at least one image per chapter and a default.jpg - metadata.json including videoId, variant, runtime, channel:"youtube", templateVersion, and chapters[{title,start,end,objectiveId?,quizDifficulty?}] - edits/ containing either edl.cmx3600 or trimlist.json matching chapter boundaries And the chapters.txt conforms to the channel template validation (timestamp format and non-empty titles) And if a connected scheduler integration is enabled, the chapters and metadata are POSTed to the scheduler endpoint, and a delivery receipt with correlationId is stored And the UI marks the export job Completed with a link to the package and the receipt
LMS Module Export with Objectives & Quiz Mapping
Given a recording with Adaptive Chapters and learning objective + quiz metadata available When the user selects Publish > LMS Module Then the system generates a package ZIP named {videoId}_{variant}_lms.zip containing: - module.json mapping chapters to LMS modules/lessons with fields {moduleId, title, objectiveIds[], estimatedDuration} - quiz.json with items grouped per chapter and difficulty scaled to the selected variant (micro=baseline-1, standard=baseline, deep-dive=baseline+1) - captions/ per-chapter .srt and .vtt files - thumbnails/ per-chapter images - edits/ edl.cmx3600 or trimlist.json aligned to chapter start/end - metadata.json with channel:"lms", templateVersion, variant and chapters[{title,start,end,objectiveIds[],quizCount}] And required fields (objectiveIds for chapters that contain quizzes) must be present or the export fails with a per-chapter validation error list And if a MAM/DAM webhook is configured, the package is delivered via POST and a delivery receipt with endpoint, status, attemptCount, and correlationId is logged and visible in the Activity feed
Podcast Show Notes Package Generation
Given a recording with Adaptive Chapters and summaries available When the user selects Publish > Podcast Show Notes Then the system generates a package ZIP named {videoId}_{variant}_podcast.zip containing: - show_notes.md with a top summary, followed by timestamped chapter entries (HH:MM:SS – Title – 1–2 sentence summary) - description.txt optimized for podcast host descriptions including total runtime and key topics - highlights.json listing top moments with start/end and shareable clip references - captions/ per-chapter .srt and .vtt files - thumbnails/ cover.jpg and per-chapter images - metadata.json with channel:"podcast", templateVersion, variant, chapters and highlights And the show_notes.md passes template validation (timestamps present, no empty entries) And if a social scheduler webhook is configured, description.txt and metadata.json are POSTed and a delivery receipt is stored and displayed
TikTok Description and Clip Export
Given a recording with a micro variant generated and vertical-safe thumbnails available When the user selects Publish > TikTok Then the system generates a package ZIP named {videoId}_micro_tiktok.zip containing: - description.txt with hashtags and a call-to-action, respecting the channel’s character and hashtag limits per template validation - clips.json listing 1–N micro highlight clips with start/end, targetDuration, and source media references - captions/ per-clip .srt and .vtt files time-bounded to each clip - thumbnails/ vertical aspect images for each clip - metadata.json with channel:"tiktok", templateVersion, variant:"micro", and clips[] And template validation ensures description length, prohibited characters, and required tags are satisfied or returns actionable errors And if a scheduler integration is configured, clips.json, description.txt, and metadata.json are POSTed and a delivery receipt with correlationId is logged
API/Webhook Handoff with Rate Limiting, Retries, and Receipts
Given per-channel rate limits are configured and a webhook endpoint is set for MAM/DAM or social scheduling When N publish jobs exceed the configured per-channel requests-per-minute threshold Then additional jobs are queued and dispatched without breaching the threshold, and any immediate HTTP 429 responses respect Retry-After headers And transient failures (HTTP 5xx, timeouts) are retried with exponential backoff and jitter up to the configured max attempts, then marked Failed with the terminal error And for each delivery attempt, a receipt is recorded with fields {correlationId, channel, endpoint, requestId, attempt, status, httpCode, durationMs, timestamp} And receipts are surfaced in the UI Activity feed and available via API for audit And secrets (API keys, tokens) are never logged in receipts or error messages
Validation, Preview, and Idempotent Re-publish
Given a user opens the Publish dialog for any supported channel template When required metadata is missing or invalid (e.g., chapter titles empty, timestamps out of order, missing objectives for LMS) Then the Publish action is disabled and inline validation lists all failing fields with per-item guidance And when all validations pass, a Preview renders the exact channel-formatted output (e.g., chapters.txt, show_notes.md) for user review And upon clicking Publish, the request includes an idempotency key composed of {videoId, variant, channel, templateVersion}; repeated publishes with the same key within the idempotency window return the original receipt without creating duplicates downstream And all generated artifacts are checksumed and recorded in metadata.json for integrity verification
Human-in-the-Loop Chapter Editor & QA
"As a reviewer, I want an editor to adjust chapters with live feedback on constraints and quality so that I can finalize high-quality outputs efficiently."
Description

Provide an interactive editor to review and adjust chapter boundaries, titles, and synopses with waveform and transcript views, live video preview, and snap-to-sentence/timecode aids. Display quality signals such as confidence scores, objective coverage heatmaps, and a runtime meter per variant. Enforce constraints with inline warnings and auto-suggested fixes; propagate edits across related variants where possible while highlighting conflicts. Support diffing between model runs, undo/redo, comments, and approvals for audit trails.

Acceptance Criteria
Adjust Chapter Boundaries with Snap Aids and Live Preview
- Given a video is loaded with generated chapters and snap-to-sentence is enabled, When the user drags a chapter boundary handle, Then the boundary snaps to the transcript sentence start timecode (rounded to nearest frame), waveform markers and transcript selection update within 100 ms, and the live preview seeks within 300 ms. - Given snap-to-timecode is enabled at a 1s grid, When the user drags a boundary, Then the boundary snaps to the nearest 1-second increment and a tooltip displays HH:MM:SS.mmm. - Given the user holds the modifier key to override snapping, When dragging a boundary, Then snapping is disabled and the boundary moves at frame-level precision with no snap indicator. - Given a boundary move would create overlap or a zero-length chapter, When the user drags past the adjacent boundary, Then the editor blocks the action, enforces a minimum duration of 2 seconds per chapter, and shows an inline warning explaining the constraint.
Edit Titles and Synopses with Validation and Autosave
- Given a chapter is selected, When the title is edited, Then the field validates 2–80 visible characters, trims leading/trailing whitespace, rejects control characters, and shows inline error until valid. - Given a chapter synopsis is edited, When the user inputs text, Then the field validates 0–300 characters, collapses multiple spaces, disallows line breaks, and prevents save on invalid input with an inline message. - Given the user stops typing or blurs the field, When 2 seconds elapse or focus changes, Then the change autosaves and a success indicator appears; on failure, a retry banner appears and the draft is preserved locally until saved. - Given the page is reloaded after a successful autosave, When the chapter is reopened, Then the most recent saved title and synopsis are present with no data loss.
Display Quality Signals: Confidence, Objective Coverage, Runtime Meter
- Given the chapter list is visible, When the editor renders chapters, Then each chapter displays a model confidence score (0–100%) with color coding: red <60, amber 60–80, green >80. - Given objective coverage heatmap is toggled on, When the timeline loads, Then segment-level coverage is displayed per learning objective with tooltips showing objective ID/name and coverage percentage, loading within 500 ms. - Given the variant has a target runtime, When chapters are added/removed or boundaries change, Then the runtime meter updates within 300 ms and color codes: green within ±5% of target, amber within ±5–10%, red beyond ±10%. - Given a user hovers any quality signal, When tooltip appears, Then it includes data source timestamp and last update time.
Enforce Constraints with Inline Warnings and Auto-Suggested Fixes
- Given a required field (title or synopsis) is empty or invalid, When the user attempts to navigate away or publish, Then an inline warning appears and an “Auto-fill suggestions” button proposes compliant text; accepting inserts the suggestion within 2 seconds. - Given the variant runtime is outside the allowed band, When the user clicks “Auto-trim/extend”, Then the editor suggests specific boundary shifts or chapter merges/additions with estimated delta to target; accepting applies changes and re-evaluates runtime immediately. - Given coverage for any Must-have objective is below 90%, When the user opens the warnings panel, Then the editor lists impacted chapters and suggests candidate sentences to include; accepting inserts/extends chapters and updates coverage. - Given all constraints are satisfied, When the user re-checks the warnings panel, Then no blocking warnings remain and the publish action is enabled.
Propagate Edits Across Variants with Conflict Highlighting
- Given micro, standard, and deep variants share canonical chapter IDs, When a user edits a chapter title in one variant, Then the change propagates to other variants that have not manually overridden that field and a confirmation toast lists affected variants. - Given a boundary edit conflicts with a locked or manually overridden chapter in a target variant, When propagation occurs, Then a conflict banner lists the variants and fields in conflict and provides per-variant options: “Keep source” or “Keep target”. - Given the user opts out of propagation, When the checkbox “Apply to related variants” is unchecked before editing, Then no changes propagate and no conflicts are recorded. - Given unresolved conflicts exist, When the user attempts bulk publish, Then the action is blocked with a link to resolve conflicts.
Diff Between Model Runs and Selective Merge
- Given two model runs are available for the same source, When the user opens Diff and selects Run A and Run B, Then the UI displays Added/Removed/Modified chapters with counts, timecode deltas, and title/synopsis differences. - Given the diff list is visible, When the user filters by change type or objective impact, Then the list updates instantly (<200 ms) to reflect the filter. - Given one or more diff items are selected, When the user clicks “Apply to draft”, Then the selected changes merge into the working draft, the timeline updates within 500 ms, and the audit log records the merge source and items. - Given the user needs external review, When “Export diff JSON” is clicked, Then a JSON file containing changes with chapter IDs, old/new values, and timecodes is downloaded.
Undo/Redo, Comments, Approvals, and Audit Trail
- Given the editor session is active, When the user performs edits (boundary moves, text edits, merges, propagations), Then undo/redo supports at least the last 50 actions with Ctrl/Cmd+Z and Ctrl/Cmd+Y/Shift+Z across all edit types. - Given collaboration is needed, When a user adds a comment on a chapter or time range, Then comments support @mentions, resolve/reopen status, and timestamps (ISO 8601); resolved threads are hidden by default with a toggle to show. - Given approval is required, When a user with Reviewer role clicks Approve on a variant, Then the system records approver, timestamp, and a content checksum; the variant status changes to Approved and any subsequent edit reverts status to Changes Pending until re-approved. - Given compliance needs, When any user action occurs, Then the audit trail records user ID, timestamp, action type, target entity, and before/after values and can be exported as CSV or JSON on request.

Mastery Loop

Closes the loop by ingesting LMS analytics (completion, dwell time, item difficulty) to suggest re-chaptering, remediation micro-clips, or objective tweaks. Publishes versioned updates back to the LMS with change logs—turning static courses into continuously improving learning experiences.

Requirements

LMS Analytics Ingestion & Normalization
"As an instructional designer, I want ClipSpark to ingest and normalize LMS analytics so that content updates are driven by real learner performance and behavior."
Description

Implement secure connectors to ingest learner analytics from major LMS platforms (e.g., completion status, dwell time by module, assessment item difficulty, attempts, and drop-off timestamps). Support LTI 1.3 Advantage, xAPI, and SCORM runtimes with OAuth2 credentials, optional mTLS, webhook and scheduled polling modes, and robust retry/throttling. Normalize incoming data into ClipSpark’s mastery schema with field mapping, per-tenant transformations, PII redaction, data retention controls, and multi-tenant isolation. Provide monitoring, alerting, and data quality checks to ensure reliable, timely inputs for downstream suggestion engines.

Acceptance Criteria
OAuth2 and mTLS Authentication for LMS Connectors
Given a tenant configured OAuth2 client_id/client_secret without mTLS, When requesting an access token, Then the request succeeds with HTTP 200 and a token valid for at least the provider-reported expiry. Given a tenant configured OAuth2 with mTLS certificates, When requesting an access token over TLS 1.2+, Then mutual TLS validates and a token is issued; requests without the client cert are rejected with HTTP 401. Given a token expiring in 5 minutes or less, When making an API call, Then the connector refreshes the token proactively and the API call succeeds without receiving HTTP 401. Given invalid OAuth2 credentials, When requesting a token, Then the system returns an AuthFailed error with no retries, emits an audit log entry, and raises an alert within 5 minutes. Given 1000 consecutive token requests under normal network conditions, When measured, Then p95 latency is 500 ms or less and success rate is 99.9% or higher. Given secrets (client_secret, refresh_token) are persisted, When stored or logged, Then they are encrypted at rest and redacted in logs.
LTI 1.3 Advantage Webhook Ingestion
Given a valid LTI 1.3 JWS-signed webhook with known iss and aud, When received, Then the signature, exp, and nonce are validated and a 2xx acknowledgment is returned within 500 ms. Given a duplicate webhook with the same eventId within 24 hours, When received, Then the event is ignored idempotently and a 2xx acknowledgment is returned. Given a valid event that requires follow-up data fetch, When the LMS responds with 429 or Retry-After, Then the connector backs off exponentially (max 5 attempts) and honors Retry-After. Given a valid event, When processed, Then a normalized record is written within 60 seconds and associated with the correct tenant and learner identifiers. Given a 5xx error from the LMS on follow-up fetch, When retries are exhausted, Then the event is moved to a dead-letter queue and an alert LTIIngestionLag is emitted.
xAPI Scheduled Polling and Parsing
Given an xAPI LRS endpoint with OAuth2 credentials, When the scheduler triggers every 5 minutes, Then the connector fetches statements using the stored since bookmark and follows pagination until completion. Given rate limiting headers (429 or Retry-After), When polling, Then the connector throttles to remain under 90% of the documented rate limit and retries with exponential backoff up to 5 times with jitter. Given retrieved statements, When parsed, Then verbs (completed, experienced, answered), results (score, success, attempts), and context are extracted and mapped to the mastery schema with required fields present. Given a network failure mid-run, When the job restarts, Then idempotency ensures no duplicate normalized records and the bookmark resumes from the last committed checkpoint. Given normal operation over 1 hour, When measured, Then p95 ingestion lag (statement timestamp to normalized record availability) is 10 minutes or less.
SCORM Runtime Data Capture and Mapping
Given SCORM 1.2 runtime data (cmi.core.lesson_status, cmi.core.total_time, cmi.core.score.raw), When ingested, Then normalized fields completion, dwell_time_seconds, and score are populated per mapping spec. Given SCORM 2004 data (cmi.completion_status, cmi.success_status, cmi.total_time, cmi.score.scaled), When ingested, Then normalized fields reflect completion, pass_fail, dwell time, and score with correct scaling to 0-100. Given multiple attempts for the same learner and SCO, When ingested, Then attempts are versioned and ordered chronologically and drop-off timestamps are computed from session data. Given paginated LMS APIs for SCORM tracking, When fetching, Then all pages are retrieved without duplication and the checkpoint is updated atomically after successful commit.
Normalization to Mastery Schema with Per-Tenant Field Mapping
Given a tenant-defined field mapping and transformation rules (version vN), When normalizing incoming records, Then output conforms to the ClipSpark mastery JSON schema and passes schema validation with all required fields present. Given a new unmapped source field, When encountered, Then the record still validates, the field is quarantined as unmapped, and a data quality warning is emitted with field name and tenant. Given a mapping change to version vN+1, When deployed, Then a change log entry is recorded and only new ingestions use vN+1 unless backfill is explicitly enabled by the tenant. Given multi-tenant operation, When storing normalized records, Then tenant partition keys are applied and cross-tenant reads are prevented; queries return only data for the caller's tenant. Given referential integrity rules, When module IDs and learner IDs are resolved, Then foreign keys must match existing catalog entries or the record is routed to a quarantine queue with reason codes.
PII Redaction and Data Retention Enforcement
Given incoming analytics containing PII (name, email, external_user_id), When normalizing, Then PII fields are redacted or tokenized per tenant policy before storage and are never written to logs. Given a tenant with a 30-day retention policy, When records exceed 30 days from ingestion, Then they are purged within 24 hours and become inaccessible via APIs, with an immutable audit log of deletions. Given a change to a tenant's redaction policy, When applied, Then subsequent ingestions follow the new policy and existing stored records are re-redacted within 24 hours if backfill is enabled. Given a data export request, When generated, Then PII remains redacted or tokenized per policy and the export contains only tenant-scoped data.
Monitoring, Alerting, and Data Quality Checks
Given normal operation, When observed in dashboards, Then metrics show per-connector ingestion rate, success/error counts, p95/p99 latency, backlog size, and age of last event per tenant. Given SLA breaches (success rate below 99% over 15 minutes or p95 lag above 10 minutes), When detected, Then alerts are sent to on-call channels within 5 minutes with diagnostic context and runbook links. Given data quality rules (required fields present, value ranges, timestamp monotonicity, duplicate detection), When violations occur, Then offending records are quarantined, reasons are attached, and a daily summary is delivered to owners. Given health checks, When /health and /ready endpoints are queried, Then they reflect connector readiness and liveness and report failures when dependent services are unavailable.
Objective-to-Content Alignment Graph
"As a content operations specialist, I want LMS objectives mapped to specific video timestamps so that analytics can pinpoint exactly where to improve."
Description

Create a mapping layer that links LMS course structures (courses, modules, learning objectives, and assessment items) to ClipSpark video chapters and timestamps. Support both automatic alignment (using transcript NLP, keyword/entity matching, and cue points) and manual curation via an editor. Maintain version-aware, bidirectional references so that analytics and recommendations target the correct content across iterations. Expose APIs for reading/writing mappings and re-index automatically when chapters or objectives change.

Acceptance Criteria
Auto-align LMS Objectives to ClipSpark Chapters
Given a published LMS course with modules and objectives (<= 50 objectives) and associated transcript-indexed videos (<= 2 hours total) And auto-alignment is initiated for the course When the NLP alignment pipeline runs Then at least 95% of objectives receive >= 1 candidate mapping to a chapter or timestamped segment with a confidence score in [0,1] And each candidate includes chapter_id, start_time, end_time, confidence, and matched_terms And the top 3 candidates per objective are returned ordered by confidence And mappings with confidence < 0.70 are flagged "needs_review" and are not auto-published And timestamp accuracy is within ±1 second of ground-truth in test fixtures And processing completes within 3 minutes wall-clock time
Curate and Override Mappings in Alignment Editor
Given a course with existing auto-generated mappings And a curator opens the alignment editor When the curator creates, edits, or deletes a mapping Then changes are persisted with user_id, timestamp, change_type, and optional rationale And manual overrides supersede auto-generated mappings for the same objective/chapter And the system validates start_time < end_time and that timestamps fall within the source media duration And the editor prevents duplicate identical mappings for the same version And the mapping change is available via GET /mappings within 5 seconds And an audit entry is visible via GET /mappings/{id}/history
Version-Aware Bidirectional References Across Iterations
Given course version v2 and ClipSpark chapter set version c3 exist alongside historical versions When querying mappings for objective_id O with no version specified Then the API returns mappings joined to the latest active LMS version and ClipSpark chapter version And when a specific version is requested (e.g., v1/c1), the API returns historical mappings including status (active|superseded|archived) And deleting a chapter or objective performs a soft delete of mappings and maintains referential integrity (no broken foreign keys) And analytics queries that reference mappings resolve to the version active at the event timestamp
Automatic Re-index on Structure Changes
Given a course with saved mappings and indexing enabled When a chapter is added, removed, reordered, or its transcript changes, or an objective is created/edited/deleted Then a re-index job is enqueued within 10 seconds and coalesces events within a 60-second debounce window And re-index preserves manual overrides and recalculates only auto-generated candidates And job status is exposed via GET /reindex/status?course_id=... and reaches "completed" within 5 minutes for courses <= 5 hours video And stale auto-generated mappings are marked "stale" and replaced with updated candidates And a "reindexed" domain event is emitted with counts of updated, stale, and created candidates
Read/Write Mapping via Secure API
Given an authenticated client with scopes mappings:read and/or mappings:write When the client calls GET /mappings with pagination and filters (objective_id, chapter_id, version, status), POST /mappings with an idempotency-key, PATCH /mappings/{id}, or DELETE /mappings/{id} Then the API enforces OAuth2 scopes and returns 401/403 for unauthorized access And validates payloads; returns 400 on invalid timestamps or unknown IDs; 409 on version conflicts; 412 on ETag mismatch And responds with p95 latency <= 500 ms for reads and <= 1000 ms for writes under 100 RPS And rate limits at 600 requests/min per token with 429 on exceed and includes a Retry-After header And all responses include version metadata (lms_version_id, chapter_version_id) and ETag headers
Many-to-Many Mapping and Conflict Resolution
Given objectives O1..On and chapters/segments S1..Sm When mappings associate multiple objectives to a single segment and multiple segments to a single objective Then the system supports many-to-many relations without duplication And each mapping may include an optional weight (0..1) and relation_type (prerequisite|direct|supplemental) And conflicts between manual and auto mappings for the same pair resolve in favor of manual, with deterministic tie-breakers by updated_at then confidence And retrieving mappings for an objective returns results sorted by manual_first, weight desc, confidence desc And exports to CSV/JSON round-trip without loss of fields or precision
Adaptive Re‑Chaptering Engine
"As a course owner, I want data-driven chapter suggestions so that learners can navigate more effectively and stay engaged."
Description

Develop a recommendation engine that proposes chapter splits, merges, and reordering based on analytics signals (dwell time valleys, high rewind zones, drop-offs, and assessment correlations) combined with semantic boundaries from transcripts (topic shifts, speaker turns). Enforce guardrails (min/max chapter length, language boundaries, content coherence), generate confidence scores, and present a visual diff preview with one-click apply or manual edit. Log rationale and metrics for each suggestion and support multilingual transcripts.

Acceptance Criteria
Split Recommendations at Analytics–Semantic Intersections
Given a video transcript with detected semantic boundaries (topic shifts, speaker turns) and LMS analytics (dwell-time valleys, high rewinds, drop-offs) When the Adaptive Re‑Chaptering Engine generates split suggestions Then a split is proposed only where at least one analytics signal and one semantic boundary occur within 15 seconds of each other And each proposed split aligns to the nearest sentence boundary within ±3 seconds And each split suggestion includes start timestamp, affected chapter ID, confidence score ∈ [0.00,1.00] with two-decimal precision, and rationale signals And each split suggestion’s confidence score is ≥ 0.70 by default threshold And if no candidates meet the threshold, the engine returns "No changes recommended"
Merge and Reorder Recommendations from Engagement Signals
Given adjacent chapters with combined duration < 4 minutes or at least one chapter < 90 seconds and no strong semantic boundary within 20 seconds of their boundary When the engine evaluates merge candidates Then a merge is proposed with confidence ≥ 0.65 and the resulting chapter respects all guardrails And the rationale lists low engagement metrics and weak boundary evidence Given a chapter with drop-off rate ≥ 30% above course average and rewind rate ≥ 20% above median, and semantic similarity ≥ 0.60 to a later chapter When the engine evaluates reorder candidates Then a reorder is proposed specifying source and destination indices, timestamps, and predicted engagement delta And reorder proposals must not reduce semantic similarity between newly adjacent chapters below 0.50
Guardrails: Chapter Length, Language, and Coherence
Rule: Minimum chapter length after applying any suggestion is ≥ 90 seconds; maximum is ≤ 15 minutes Rule: Splits occur only at sentence boundaries; no split inside a word/token Rule: Suggestions must not cross detected language segment boundaries; merges and reorders between different languages are disallowed Rule: Post-suggestion intra-chapter topical coherence score (average sentence embedding similarity) is ≥ 0.50 for every chapter Rule: Suggestions that would violate a guardrail are automatically discarded and logged with reason = "GuardrailViolation"
Visual Diff Preview and One‑Click Apply/Manual Edit
Given a set of proposed splits, merges, and reorders When the user opens the visual diff Then each change is labeled by type (Add/Split/Merge/Move) with before/after timestamps and chapter indices And accepting/rejecting individual suggestions updates the preview counts within 300 ms And clicking "Apply All" applies accepted suggestions to a new draft version in ≤ 3 seconds for videos up to 2 hours And manual boundary edits (drag handles or timestamp input) are permitted before apply and are included in the applied draft And after apply, the resulting chapter list matches the preview exactly and a new draft version ID is displayed
Rationale and Metrics Logging for Every Suggestion
Given suggestions are generated or applied When the system logs the event Then each suggestion record includes: action type ∈ {split, merge, reorder}, affected chapter IDs/indices, timestamps, confidence, threshold, contributing analytics signals with magnitudes, semantic boundary types, model version, processing time, dataset/video ID, and user ID (on apply) And an audit API can retrieve a suggestion record by ID in ≤ 200 ms And each applied set writes a change log entry with before/after chapter maps and rationale summary And logs are retained for ≥ 365 days and are exportable as JSON
Multilingual Transcript Handling
Given a transcript containing multiple language segments with per-segment language tags When the engine generates suggestions Then no suggestion splits inside a word for any supported language And suggestions do not merge or reorder chapters across language segment boundaries And sentence boundary detection respects language-specific punctuation (e.g., 。, ؟, ¡) And for right-to-left languages, text and timestamps are correctly ordered in the diff preview And each suggestion’s rationale includes the language code of the segment it pertains to
Remediation Micro‑Clip Generator
"As a learning engineer, I want automatic remediation micro-clips for difficult topics so that learners can quickly close knowledge gaps."
Description

Automatically generate targeted micro-clips for concepts exhibiting low assessment performance or high confusion signals. Select context-rich segments, add optional overlays (callouts, lower-thirds), and produce captions and titles. Package micro-clips with metadata (objective IDs, tags, prerequisites) and publish them back to the LMS as supplemental resources with release rules (e.g., auto-assign upon failed quiz). Track consumption and subsequent learner performance to close the remediation loop.

Acceptance Criteria
Auto-Detection of Remediation Targets from LMS Analytics
Given LMS analytics thresholds are configured (quiz_correctness < 70%, dwell_time ≥ 1.5x baseline, item_difficulty > 0.75) When the nightly analytics import completes for a course Then all concepts meeting any threshold are flagged for remediation And a micro-clip generation job is queued per flagged concept within 10 minutes And each job includes courseId, objectiveId, sourceVideoIds, and triggeringMetrics And at least 95% of eligible concepts yield successfully queued jobs in the run
Context-Rich Segment Selection for Micro-Clip
Given a flagged concept with aligned transcript and timestamps When the micro-clip generator selects a segment Then the segment duration is between 30 and 120 seconds (configurable) And includes at least 5 seconds of lead-in before the first concept mention and 5 seconds of follow-through after the final explanation (when available) And the average ASR confidence over the segment is ≥ 0.90 And the segment does not overlap > 60% with any existing micro-clip for the same objective And the segment starts and ends on sentence boundaries
Overlay Rendering and Styling Compliance
Given the project overlay policy is Enabled with style "Default EDU" When the micro-clip is rendered Then a key-term callout appears within the first 10 seconds (if a key term is detected) And a lower-third shows speakerName and objectiveTitle for 3–5 seconds on first appearance And visual elements respect a 60px safe-margin and do not overlap the caption area And disabling overlays in the policy produces a render with no overlays
Captions and Title Generation Quality
Given the micro-clip has been rendered When captions and a title are generated Then median caption timing error is < 200 ms and line length ≤ 42 characters And ASR confidence is ≥ 0.92 over ≥ 90% of caption lines And the title length is between 30 and 80 characters, includes the objective keyword, and passes profanity checks And captions and title pass accessibility checks (e.g., caption background ensures contrast ratio ≥ 4.5:1)
Metadata Packaging and LMS Schema Compliance
Given a micro-clip is ready for publish When metadata is packaged Then the package includes objectiveId, tags (≥ 2), prerequisites (0+), language, duration, releaseRules, and contentHash And the objectiveId maps to an existing LMS objective (lookup returns 200) And the package validates against the LMS schema (HTTP 200/Created) without warnings And contentHash changes when any audio, video, or caption content changes
Rule-Based Publishing and Auto-Assignment on Quiz Failure
Given a release rule "Auto-assign on quiz failure" is configured for quizId QZ-101 with threshold < 70% When a learner submits a quiz attempt below the threshold Then the corresponding micro-clip is assigned within 5 minutes and appears in the learner’s LMS supplemental resources And learners who meet or exceed the threshold are not assigned the micro-clip And the publish response returns a new resourceVersion with a changeLog entry (reason, ruleId, timestamp, author=system)
Consumption Tracking and Performance Impact Attribution
Given micro-clips have been assigned When learners view an assigned micro-clip and retake the related assessment within 14 days Then consumption events (start, 25%, 50%, 75%, 100%) are recorded with userId, clipId, timestamp And events are successfully delivered to the analytics store within 2 minutes of occurrence And the system links the post-view assessment to the clip via objectiveId and reports score_delta = post - pre And aggregate report shows improvement metrics by cohort and objective, and flags objectives with no improvement for re-chaptering suggestions
Learning Objective Tuning Assistant
"As a curriculum designer, I want evidence-based objective recommendations so that course goals remain clear, measurable, and achievable."
Description

Provide AI-driven recommendations to refine learning objectives based on performance data (item difficulty, mastery rates, time-to-mastery). Suggest clearer verbs, appropriate Bloom’s level, splitting compound objectives, or adjusting scope. Offer evidence for each recommendation and preview impacts on aligned assessments. Support draft/approve workflows and publish objective updates to the LMS, recording rationale and maintaining traceability.

Acceptance Criteria
Generate Objective Recommendations from Performance Data
Given LMS analytics provide item difficulty, mastery rate, and time-to-mastery per objective for a selected date range and cohort When the user runs the Learning Objective Tuning Assistant for the course Then the system generates recommendations per objective that include suggested change text, an aligned Bloom’s level, a recommendation type tag (Verb/Scope/Split), and a confidence score between 0.0 and 1.0 And objectives lacking sufficient data are labeled "Insufficient evidence" with no change suggested And recommendations are reproducible for the same input filters (cohort, date range)
Evidence and Rationale Display for Each Recommendation
Given a recommendation has been generated for an objective When the user opens the recommendation details Then the system displays the evidence set including current mastery rate (%), median time-to-mastery, item difficulty distribution, sample size (n), and the applied filters (date range, cohort) And the system lists at least the top 3 aligned assessment items contributing to the evidence with links/IDs And the system renders a one-sentence rationale template: "Because [metric comparator and value], we recommend [change]" And the evidence snapshot is stored so that it remains consistent even if analytics subsequently change
Assessment Impact Preview Before Applying Objective Changes
Given the user has one or more pending objective edits in a draft When the user clicks Preview Impacts Then the system shows a redline diff of the objective text (before vs. after) And lists all impacted artifacts with counts: aligned items, chapters/micro-clips, and learning paths And calculates and displays coverage change (number of aligned items before vs. after) and flags any Bloom level mismatches And provides an exportable impact report (CSV/JSON) containing the diff, impacted artifact IDs, and coverage metrics
Draft, Review, and Approval Workflow for Objective Changes
Given a user with Author role saves edits to objectives When the edits are saved as a draft Then the system assigns a version label (e.g., vX+1-draft) and records author and timestamp And the author can request review by selecting approvers and setting a due date When an Approver reviews the draft Then they can Approve or Request Changes with a required comment And only Approved drafts become eligible for publish; Rejected drafts return to Draft status with tracked rationale And all actions (save, request review, approve/reject) are logged with user, timestamp, and version
Publish Approved Objective Updates to LMS with Versioning and Change Log
Given an objective draft has Approved status When the user initiates Publish Then the system pushes updates to the LMS via API and returns a confirmation including the LMS objective ID and LMS version identifier within 60 seconds And the system creates a change log entry containing before/after objective text, rationale, author, approver, timestamps, evidence snapshot ID, and impacted artifact list And the local version transitions from vX+1-draft to vX+1 with a permanent, immutable record If the LMS API fails, then no new version is created, the draft remains Approved, the user sees the error code/message, and a retry option is available without creating duplicate LMS versions
End-to-End Traceability and History Retrieval
Given an objective exists in the system When the user opens the History view for that objective Then the system displays a chronological ledger of recommendations, decisions, drafts, approvals, publishes, and rollbacks with user, timestamp, version, and links to evidence and impact reports And the user can filter history by date range, version, decision status, and actor And the user can export the full trace (JSON/CSV) including IDs needed to reconcile with the LMS (objective ID, version IDs) And the trace remains accessible after subsequent publishes and is read-only
Versioned Publishing & Change Logs
"As a compliance trainer, I want versioned publishing with detailed change logs so that I can maintain auditability and control over updates."
Description

Enable semantic versioning for courses, chapters, micro-clips, and objectives. Publish approved changes back to the LMS via LTI Deep Linking and LMS REST APIs with idempotent operations. Auto-generate human-readable and machine-readable change logs detailing before/after chapter structures, micro-clips added, and objective edits. Provide approval gates, rollback to prior versions, and a complete audit trail to satisfy compliance and review requirements.

Acceptance Criteria
Semantic Versioning Enforcement
Rule: All artifact versions (course, chapter, micro-clip, objective) must match ^\d+\.\d+\.\d+$ and be unique per artifact. Rule: MAJOR increment when removing/renaming chapters or objectives, changing objective alignment mappings, or altering LTI placements that break existing links. Rule: MINOR increment when adding chapters/micro-clips/objectives or reordering chapters without removals. Rule: PATCH increment for copy/metadata fixes (typos, descriptions, thumbnails) that do not alter objectives or structure. Given a working copy with changes, When saved, Then the proposed next version reflects the correct semantic increment and cannot be manually downgraded. Given a published version, When viewed, Then its content is immutable (read-only) and remains retrievable. Given no changes since the last published version, When attempting to publish, Then the system blocks publish with message "No changes detected".
Idempotent LTI Deep Linking + REST Publish
Given an approved version with LMS resource mappings, When Publish is triggered, Then all LTI Deep Linking and LMS REST operations return success (2xx) and each item is upserted exactly once. Given the same publish is triggered again with no content changes, Then no duplicate LMS entities are created, and the publish log records a no-op with the same deduplication checksum. Given transient network errors, When requests are retried, Then idempotency keys ensure a single side effect per item across retries. Then the publish job summary reports counts: created=X, updated=Y, unchanged=Z; on immediate re-publish with no changes, created=0 and updated=0. Then the LMS items reflect the ClipSpark version number in supported metadata fields (e.g., custom parameters, description, or notes).
Human-Readable Change Log Generation
When a version is approved, Then a human-readable change log is generated with: version, author, approver(s), approval timestamp, publish timestamp, and summary. Then the log includes a before/after chapter outline highlighting added/removed/moved items. Then the log lists micro-clips added with timestamps, durations, and source video references. Then the log lists objective edits showing previous and new wording. Then the log is accessible in the UI, and exportable as PDF and Markdown. Then, when supported by the LMS, the log (or link) is attached to the published item.
Machine-Readable Change Log (JSON Schema)
Then a JSON change log is produced for each publish with fields: artifact_type, artifact_id, from_version, to_version, actor, approved_by, approved_at, published_at, changes[]. Then each change entry has: type in {add, remove, update, move}, path (JSON Pointer), before, after, and object_ids. Then the JSON validates 100% against the published schema (v1.0) and uses ISO 8601 UTC timestamps. Then the document is stored in the audit record and exposed at GET /api/v1/changes/{artifact_id}/{to_version} with authz, and is included in the publish payload to the LMS when supported.
Approval Gate and Roles
Given an approval policy requiring at least 1 Owner and 1 SME approval, When approvals are incomplete, Then the Publish action is disabled with an explanation of unmet requirements. When an approval is recorded, Then it includes role, decision (approve/reject), comment, and timestamp; withdrawing an approval re-locks publishing. Then only users with the Publisher role can trigger Publish once approvals are satisfied. Then all approval events are captured immutably in the audit trail and are visible in the change log.
Rollback to Prior Version
Given a published version Vn and a prior version Vk (k < n), When a user with Publisher role initiates rollback to Vk, Then a new version V(n+1) is created with content identical to Vk and a change log entry "Rollback to Vk". Then rollback is blocked if the working copy has unapproved changes, with options to discard or save as draft. Then publishing V(n+1) updates LMS resources via idempotent upserts without creating duplicates. Then the audit trail links V(n+1) to Vk and Vn, recording actor, reason, and timestamps.
Publish Failure Handling and Retry
Given partial LMS API failures during publish, When the job runs, Then failed items are retried up to 3 times with exponential backoff and idempotency keys. Then the job completes as Succeeded if all items succeed after retries; otherwise status is Partially Failed with exact counts of failed items. Then the system guarantees no duplicates or orphaned LMS items post-retry by reconciling expected vs actual resource IDs. Then the UI provides a per-item error report and a Resume Publish action that retries only failed items using the original idempotency keys.
Impact Analytics & A/B Tracking Dashboard
"As a program manager, I want to see the measured impact of each change so that I can validate improvements and prioritize future iterations."
Description

Deliver a dashboard to measure the effect of applied changes versus prior versions or control groups. Support A/B or phased rollouts and track KPIs such as completion rate, average dwell time, quiz pass rate, and time-to-completion. Provide cohort segmentation, privacy-preserving aggregation, and statistical significance indicators. Allow scheduling, early-stop rules, and auto-promotion of winning variants, with exportable reports for stakeholders.

Acceptance Criteria
Variant Setup & Traffic Allocation
Given a course owner creates Experiment E with variants A (control) and B (treatment) and selects KPIs (completion rate, average dwell time, quiz pass rate, time-to-completion), When they set traffic split to 50/50 for cohort "All enrolled in Course X" and click Start, Then the experiment status changes to "Running" within 5 minutes, both variants begin receiving traffic, and an assignment counter for each variant updates at least every 10 minutes. Then at least 98% of eligible learners are assigned to exactly one variant and the assignment persists for 30 days or until experiment end, whichever comes first. Then crossover contamination is ≤2% and unassigned eligible learners are ≤1%. When the experiment is Paused or Resumed, Then status updates within 1 minute and no new exposures are logged while Paused.
KPI Computation & Dashboard Accuracy
Given event data is ingested, When at least 100 exposures per variant have been recorded, Then the dashboard shows per-variant KPIs with definitions: completion rate = completed learners / exposed learners; average dwell time = total dwell minutes / exposed learners; quiz pass rate = passes / quiz takers; time-to-completion = median minutes to completion. Then KPI values match validated warehouse aggregates within ±1% for counts/ratios and ±2% for durations/medians over the same time window. Then KPI refresh latency is ≤10 minutes from event arrival. When a date range filter is applied, Then KPIs recalculate correctly and the query completes in ≤5 seconds for up to 100k exposures.
Statistical Significance & Guardrails
Given a target MDE and a primary KPI are configured, When an experiment is running, Then the dashboard displays for each KPI: variant uplift, 95% confidence interval, p-value, and current power estimate. Then the "Significant" badge appears only when p<0.05, per-variant sample size ≥ the precomputed minimum for the configured MDE, and minimum runtime ≥ 7 days. Then guardrail alerts trigger if quiz pass rate decreases by ≥3% absolute with p<0.05 or average dwell time decreases by ≥5% with p<0.05 in the treatment variant. When guardrail alerts trigger, Then the experiment is flagged and early-stop rules (if enabled) are evaluated.
Cohort Segmentation & Privacy-Preserving Aggregation
Given cohort filters (role, region, device type, enrollment date, instructor, language) are available, When a user applies one or more filters, Then per-variant KPIs, uplift, and significance recalculate for the filtered cohort. Then any cohort cell with unique learners <10 is suppressed (metrics hidden and replaced with "Insufficient data") and, if applicable, rolled into an "Other" bucket. Then no PII (name, email, exact user ID) appears in the UI or exports; only aggregated counts and rates are shown. Then aggregation outputs are rounded to 1 decimal place and randomized rounding/noise is applied such that per-cell perturbation is ≤0.5 percentage points for cells ≥1,000 learners. Then all cohort-filtered queries for ≤50k exposures complete in ≤7 seconds.
Scheduling & Early-Stop Automation
Given a user schedules Experiment E to start on a future date/time and defines early-stop rules (primary KPI significance p<0.05, min per-variant n≥500, min runtime 7 days), When the start time arrives, Then the experiment begins within 2 minutes and traffic is allocated per plan. When early-stop criteria are met, Then the experiment automatically stops within 10 minutes, a winner is declared on the primary KPI, and notifications are sent via email and in-app to project members. When a guardrail breach early-stop condition is met, Then the experiment auto-stops and labels the result "Stopped by guardrail." Then all automatic actions are logged with timestamp, actor=system, and rule references.
Auto-Promotion & LMS Versioned Publish
Given auto-promotion is enabled and a winner is declared with guardrails satisfied, When the experiment stops, Then traffic is shifted to 100% for the winning variant within 10 minutes. Then a new course version is published to the LMS via API with version tag incremented (e.g., v1.3 → v1.4), and a change log entry includes variant summary, KPI uplifts, sample sizes, and decision rationale. Then learners in progress remain uninterrupted, and new learners receive the promoted version only. Then a one-click rollback restores the previous version within 10 minutes and updates the change log accordingly.
Exportable Reports & Audit Trail
Given an experiment has run, When a user exports a report (PDF and CSV/JSON), Then the file includes experiment metadata, configuration, per-variant KPIs, cohort filters applied, statistical results (uplift, CI, p-values), decision status, and change log summary. Then exports exclude PII and per-cohort cells with n<10; files are generated in ≤60 seconds for up to 10k exposures and are ≤5 MB. Then an immutable audit log records experiment creation, configuration changes, status changes, auto-stops, promotions, and rollbacks with user/system actor, timestamp (UTC), and before/after values, retained for ≥365 days. When an export is requested, Then a corresponding audit log entry is created.

Smart Teasers

Auto-generate metered previews that hook viewers without giving away the core value. Choose preset lengths (10s/30s/custom), let AI pick the most persuasive moments, and block seeking beyond the preview. Add overlay CTAs and countdowns to nudge purchase. Outcome: higher conversion with zero manual clipping.

Requirements

Teaser Duration Presets & Customization
"As a creator repurposing recordings, I want to quickly choose a teaser length that fits my audience so that I can publish previews without manual clipping."
Description

Provide a duration selector with presets (10s, 30s) and a custom input (3–60s) that validates against video length and product limits. Persist selection at the project/video level with workspace defaults. Store chosen duration as metadata used by the rendering pipeline and the player’s metering logic. Expose settings via UI and API, including rounding rules to align custom durations to keyframes for glitch‑free playback. Ensure responsiveness on web/mobile and support bulk-apply across a library.

Acceptance Criteria
UI Preset Duration Selection (10s/30s)
Given a video of length V seconds in Smart Teasers settings And product max teaser duration is 60 seconds When the presets are rendered Then the 10s preset is enabled if V >= 10 And the 30s preset is enabled if V >= 30 And any preset with value > min(V, 60) is disabled with an explanatory tooltip When the user selects an enabled preset and saves Then the selection persists and displays as selected on subsequent loads
Custom Duration Input Validation (3–60s)
Given a video length V and product max 60 seconds When the user enters a custom value N (in seconds) Then the system accepts integers between 3 and min(V, 60) inclusive And rejects values < 3, > min(V, 60), non-numeric, or empty And shows an inline error message and disables Save until corrected When a valid N is saved Then the value is stored as requestedDuration for that video
Workspace Defaults and Overrides Persistence
Given a workspace default duration D is set And a new project P is created without an override Then P inherits D as its default duration When P sets a project-level default P_D Then videos in P without a video-level setting use P_D When a video sets a video-level duration V_D Then V_D overrides P_D and D And changes persist across sessions and devices And updating D later does not overwrite existing P_D or V_D
Metadata and Downstream Usage (Rendering & Player Metering)
Given a video with requestedDuration N and effectiveDuration E after keyframe rounding When a render job is created Then metadata includes requestedDuration=N and effectiveDuration=E And the rendered teaser duration equals E ±100ms When the player loads the teaser Then playback stops at or before E +100ms And seeking/scrubbing beyond E is blocked by metering logic
Keyframe-Safe Rounding Behavior
Given a requestedDuration N that does not align to a keyframe When computing effectiveDuration Then the system snaps to the nearest preceding keyframe timestamp K such that K <= N And effectiveDuration = K And effectiveDuration >= 3 seconds after snapping And the UI/API surface both requestedDuration and effectiveDuration And the UI indicates when snapping has occurred (e.g., "Snapped to keyframe")
Public API for Teaser Duration Settings
Given an authenticated API client When it POSTs/PUTs teaser duration with either preset:"10s"|"30s" or customSeconds:N and scope: workspace|project|video Then the API validates N within [3, min(videoLength, 60)] And applies keyframe rounding to compute effectiveDuration And responds 200 with requestedDuration, effectiveDuration, roundingMode:"floor_to_keyframe", scopeApplied, and source:"workspace_default"|"project"|"video" And on validation failure responds 422 with machine-readable error codes and messages And GET endpoints return the resolved duration for a video including inheritance source
Responsive UI and Bulk Apply Across Library
Given the duration control UI When viewed on desktop (≥1024px), tablet (≥768px), and mobile (≤767px) Then controls are usable without horizontal scrolling, touch targets are ≥44px on mobile, and labels/validation messages do not overlap Given a user selects multiple videos in the library and chooses Bulk Apply with a preset or valid custom value When the operation runs Then durations are applied to all eligible videos And ineligible videos (e.g., shorter than requested or exceeding product limits) are skipped with reasons And a summary reports counts of applied and skipped items And the operation is idempotent if re-run with the same parameters
Persuasive Moment Detection & Ranking
"As a podcaster, I want the AI to pick the most persuasive moments for a short teaser so that viewers are hooked without me reviewing the whole episode."
Description

Leverage ClipSpark’s transcript, speaker diarization, and highlight models to identify and score compelling moments that maximize curiosity while excluding core value segments. Generate top N candidate ranges per requested duration with diversity constraints, spoiler avoidance, and sentiment/excitement signals. Provide deterministic outputs via seed option, with fallbacks for low-signal videos. Return timestamps, confidence scores, and rationale snippets to power preview, regenerate, and analytics features.

Acceptance Criteria
Generate Top-N Candidate Ranges by Duration
- Given a requested preview duration (10s/30s/custom) and N, when analysis completes, then exactly N candidate ranges are returned if available; otherwise all available candidates are returned and a reason="insufficient_candidates" is included. - Each candidate duration is within ±1.0s of the requested duration and within video bounds (0 ≤ start < end ≤ video_duration). - Each candidate includes fields: start_time_ms, end_time_ms, duration_ms, confidence (0–1), curiosity_score (0–1), spoiler_risk (0–1), rank (1..N), seed_used, primary_speakers[], rationale_snippet. - start_time_ms and end_time_ms align to transcript timebase within ±100 ms. - Response generation completes within 5s P95 for videos ≤ 30 min and 12s P95 for videos ≤ 120 min in production conditions.
Enforce Diversity Across Candidates
- Overlap between any two candidates is ≤ 20% of the shorter candidate’s duration. - At least 80% of candidates have distinct primary_speakers or distinct topic clusters (topic_diversity_score ≥ 0.6). - No more than 1 candidate originates from the same contiguous 2-minute section unless N > 5, in which case max 2. - If diversity constraints cannot be fully satisfied, response sets diversity_relaxed=true and lists violated_rules[].
Avoid Core Value Spoilers
- Aggregate overlap with segments labeled core_value=true is ≤ 5% of the candidate duration and ≤ 2.0s, whichever is smaller, for every candidate. - Candidates have spoiler_risk ≤ 0.20; any candidate exceeding this threshold is excluded from the top N. - When exclude_markers are provided, candidates have zero overlap with those spans. - If exclusion eliminates all candidates, system returns empty list with code="insufficient_content" and explanation, not a 5xx error.
Rank by Curiosity and Provide Rationale
- Candidates are ordered strictly by curiosity_score (desc); ties are broken by higher confidence, then greater diversity contribution. - The top 3 candidates (or all if N < 3) each have curiosity_score ≥ 0.65. - Each candidate includes a rationale_snippet of 15–40 words that references at least one cue (e.g., question, unresolved claim, contrast) and maps to transcript tokens by offset indices. - confidence, curiosity_score, and excitement_score are present per candidate within [0,1] and computed from transcript, diarization, and highlight signals.
Deterministic Outputs via Seed
- Given identical video, transcript, parameters, and seed, repeated runs return byte-for-byte identical candidate lists, scores, and ordering. - Given identical inputs with different seeds, at least 60% of the top N candidates differ by timestamp or rank. - The request seed is echoed as seed_used; if no seed supplied, seed_used is null and response includes non_deterministic=true.
Low-Signal Fallback Behavior & Flags
- When persuasive signals are below threshold, response sets low_signal=true and strategy ∈ {"structural","speaker_change","silence_gap"}. - In low-signal mode, system still returns at least min(3, N) candidates if video_duration ≥ requested_duration × min(3, N); otherwise returns code="insufficient_content" with explanation. - Fallback candidates still satisfy spoiler avoidance and diversity constraints. - All error states are returned with HTTP 200 and code field; no unhandled exceptions or 5xx due solely to content paucity.
Metered Playback Guard (Seek & Scrub Blocking)
"As a course creator, I want viewers to be unable to watch past the preview so that the full content remains paywalled until purchase."
Description

Implement player-level enforcement that limits playback to the teaser window and blocks seeking, scrubbing, or keyboard shortcuts beyond the allowed timestamp. Support HLS/DASH with segment-aware boundaries, signed URLs, and optional tokenized manifests to prevent direct file access. Cover desktop and mobile web, handle edge cases like buffering near the boundary, and display a standardized end-of-preview state. Provide SDK hooks/events for analytics and paywall triggers.

Acceptance Criteria
Segment-Aware Teaser Boundary Enforcement (HLS/DASH)
Given a video has a configured teaser window [teaserStart, teaserEnd] and an HLS or DASH manifest is loaded When playback begins within the teaser window Then playback is clamped so the playhead never renders content before teaserStart or beyond teaserEnd by more than 250ms And the player MUST NOT request or download any media segments whose startTime >= teaserEnd And if a segment overlaps teaserEnd, the player MUST NOT render frames beyond teaserEnd (truncate or skip overlapping portion) And network logs show zero HTTP requests for segments starting at/after teaserEnd and zero rendered duration beyond teaserEnd
Seek/Scrub/Keyboard/Gesture Blocking
Given a user attempts to move the playhead beyond teaserEnd via progress bar click/drag, keyboard shortcuts (ArrowRight, L, End), or mobile gestures (double-tap seek, swipe) When the requested seek target > teaserEnd Then the seek is clamped to teaserEnd and no content beyond teaserEnd is rendered (audio or video) And the scrubber snaps back/clamps within 200ms and an inline notice indicates "Preview ended" And an onSeekBlocked event is emitted with {attemptedTime, clampedTime, inputMethod} And playback does not resume unless the playhead is moved within the teaser window
Signed URL and Tokenized Manifest Protection
Given manifest and segment URLs require a valid signature or access token scoped to the teaser window When a client requests the manifest or any segment without a token or with an expired/invalid signature Then the server responds 401/403 and the player transitions to the end-of-preview state (not a generic error screen) And tokens issued for preview sessions cannot fetch segments whose startTime >= teaserEnd (requests are denied) And direct access attempts to the media playlist or file outside the player are denied (401/403) And token TTL and allowed clock skew (<=60s) are enforced and observable in server logs
Buffering Near Boundary and No-Leak Guarantee
Given network conditions or prefetching have buffered content beyond teaserEnd When playback approaches teaserEnd Then no audible or visual frames beyond teaserEnd are rendered and the maximum playhead overshoot is <=250ms before clamping/pausing And the onBoundaryHit event fires exactly once per session with {wallClockTime, playheadTime, bufferedRanges} And replaying or scrubbing within the teaser window continues to enforce the boundary without leaks
Standardized End-of-Preview State (Overlay, CTA, Countdown)
Given playback reaches teaserEnd or a seek beyond teaserEnd is attempted When the boundary is hit Then a standardized overlay appears within 300ms showing title, optional countdown (if configured), and primary CTA And transport controls are disabled except replay within the teaser window And focus moves to the CTA for keyboard users; screen readers announce the end-of-preview And an onPaywallShown event is emitted once with {context:"boundary", source:"auto"}
SDK Hooks and Analytics Events
Given the SDK is integrated in a host page When teaser playback starts, the boundary is hit, a seek is blocked, the overlay is shown, or replay occurs Then the SDK emits onTeaserStart, onBoundaryHit, onSeekBlocked, onPaywallShown, and onReplay respectively And each event payload includes {sessionId, videoId, teaserStart, teaserEnd, playheadTime, userAgent, inputMethod?} And events are emitted at most once per action, in order: onTeaserStart -> onBoundaryHit -> onPaywallShown, and are available via callbacks and postMessage for iframes
Cross-Browser and Mobile Web Support
Given modern desktop browsers (Chrome, Safari, Firefox, Edge latest two versions) and mobile Safari/Chrome on iOS/Android When playing HLS (native or via MSE) and DASH streams with the guard enabled Then boundary enforcement, seek blocking, overlay behavior, and SDK events work consistently within stated tolerances across all tested browsers And touch gestures are blocked/clamped as specified and accessibility roles/labels remain valid And there are no console errors or unhandled promise rejections during normal preview flow
CTA Overlay & Countdown
"As a marketer, I want an on-video countdown and clear CTAs so that viewers are nudged to convert right when interest peaks."
Description

Render configurable, brandable overlays that appear during the teaser and at the boundary, including a countdown timer, headline, subtext, and up to two CTA buttons (e.g., Subscribe, Unlock Full Video). Support themes, localization, accessibility (WCAG), and mobile-safe tap targets. Allow deep links to checkout/trial pages with tracking parameters. Trigger events on view, click, and end-of-preview for analytics and experimentation.

Acceptance Criteria
Overlay Rendering & Content (Teaser and Boundary)
Given a Smart Teaser playback session with overlay configuration including headline, subtext, countdown timer enabled, and 0–2 CTA buttons When the teaser starts Then the overlay appears within 200 ms and displays the configured headline and subtext exactly as provided Given 0, 1, or 2 CTAs configured with labels and order When the overlay renders Then exactly that number of CTA buttons appear in the specified order, with labels matching the configuration Given a defined preview end time When the teaser is playing Then the countdown shows remaining time in mm:ss and updates at least once per second with drift ≤ 250 ms relative to the video time When the teaser is paused or buffering Then the countdown pauses and resumes in sync with playback When the teaser segment ends Then the overlay remains visible until boundary gate behavior takes over
Boundary Countdown Gate & Seek Blocking
Given a preview boundary at t_end When currentTime reaches t_end Then playback pauses within 100 ms and a boundary gate overlay with countdown and CTAs is displayed Then the countdown reaches 00:00 ± 250 ms at the moment playback halts When the user attempts to seek beyond t_end via UI, keyboard, or API Then the seek is clamped to t_end − 0.1 s and playback remains blocked beyond t_end When the user seeks to any time before t_end Then playback resumes normally When the player "Play" control is activated after reaching t_end Then playback does not progress past t_end Then CTA buttons on the boundary overlay remain clickable while playback is blocked
Theme Application & Brand Controls
Given a theme configuration specifying primary/secondary/background/text colors, font family, button shape (corner radius), and overlay opacity When the overlay renders Then the specified tokens are applied to headline, subtext, countdown, and CTA buttons Given any missing or invalid theme token When the overlay renders Then a documented default value is used without visual breakage or console errors When interacting with CTA buttons Then normal, hover, pressed, and focus visual states are rendered using the theme tokens When switching between light and dark theme presets at runtime Then the overlay updates within 300 ms without a player reload
Localization & RTL Text Handling
Given a selected locale (e.g., en-US, fr-FR, ar-SA) When the overlay renders Then headline, subtext, CTA labels, and countdown units display in the selected locale When rendering an RTL locale (e.g., ar-SA, he-IL) Then text alignment, reading order, and CTA order mirror appropriately, and the layout uses dir=rtl Given localized number formats When the countdown renders Then numerals follow the locale conventions Given a missing translation key When the overlay renders Then the default locale string is used and no raw key or placeholder is shown
Accessibility (WCAG 2.2 AA) Compliance
Given the overlay is visible When evaluated for contrast Then body text has contrast ≥ 4.5:1 and interactive component non-text contrast ≥ 3:1 Given keyboard-only navigation When tabbing through the overlay Then all interactive elements are reachable in a logical order and a visible focus indicator (≥ 2 px, contrast ≥ 3:1) is shown Given screen reader users When the overlay appears Then the overlay region is announced with headline and subtext, and CTA buttons have accessible names matching their labels Given the countdown timer When it updates Then updates are announced via aria-live="polite" no more than once per second with the label "Preview ends in {n} seconds" Given the boundary gate overlay When it activates at t_end Then it behaves as a modal (focus contained within the overlay) and focus returns to the previously focused element when the overlay is dismissed
Mobile Tap Targets & Responsive Layout
Given a mobile viewport ≤ 480 px width When the overlay renders Then each CTA has a minimum touch target of 44 × 44 dp with ≥ 8 dp spacing between targets Given devices with display cutouts or system gesture areas When the overlay renders Then all content and tappable regions respect safe-area insets and are not obscured Given two CTAs and insufficient horizontal space for minimum targets When the layout is computed Then CTAs stack vertically in configured order without overlap or clipping Given a device orientation change When it occurs during teaser playback Then the overlay reflows within 250 ms and remains fully operable
Deep Links & Analytics Instrumentation
Given a CTA configured with a base URL and tracking parameters (e.g., utm_source, campaign, teaser_id) When the user activates the CTA Then the opened URL includes all tracking parameters correctly URL-encoded and preserves existing query parameters without duplication Given a CTA URL using a non-http/https scheme When the configuration is validated Then it is rejected with a validation error and the CTA is not rendered When the overlay first renders in a session Then an event "overlay_view" is emitted with payload: video_id, teaser_id, locale, theme_id, timestamp When a CTA is activated Then an event "cta_click" is emitted with payload: video_id, teaser_id, cta_id, cta_label, url, timestamp When playback reaches the preview boundary and is blocked Then an event "preview_end" is emitted with payload: video_id, teaser_id, timestamp Then all events are dispatched within 300 ms of the triggering action and deduplicated for identical events within a 10-second session window
One-Click Approve/Regenerate Workflow
"As an editor, I want to approve or regenerate a teaser in one place so that I can publish quickly without manual edits."
Description

Provide a review screen that instantly previews the AI-selected teaser, with options to approve, regenerate alternatives, or fine-tune by excluding topics/keywords. Show candidate list with confidence, waveform/transcript context, and side-by-side comparison. Maintain version history and allow rollback. On approval, trigger server-side clip rendering and update player configuration without re-uploading source media.

Acceptance Criteria
Instant Teaser Preview on Review Screen Load
Given a video with an AI-selected teaser exists and the user opens the Smart Teasers review screen When the review screen loads Then the top-ranked candidate's first frame is visible within 2 seconds and playback starts muted within 3 seconds And the displayed duration matches the selected preset (10s/30s/custom) within ±0.5s And the transcript captions are time-synced to audio within ±200 ms for at least 95% of the teaser duration And a waveform for the candidate region is displayed with the current playhead indicator And the candidate's start and end timestamps are shown with millisecond precision And changing the preset updates the previewed segment and duration within 2 seconds
One-Click Approve Triggers Render and Player Update
Given a candidate teaser is selected When the user clicks Approve Then a render job is queued within 1 second and its status is displayed (Queued, Rendering, Completed) And the server-side clip render completes within 2 minutes for teasers ≤30 seconds at the 95th percentile And upon completion, the player configuration is updated to reference the new teaser without re-uploading the source media And the player is configured to meter the teaser and block seeking beyond its end And the UI displays a success confirmation and the approved teaser is marked as "Approved" with a version ID
Regenerate Produces Distinct Alternatives with Confidence
Given the user clicks Regenerate When alternatives are generated Then at least 3 and at most 5 new candidates are returned within 15 seconds And each candidate includes start/end timestamps, duration, confidence score (0.00–1.00), and a transcript snippet And no two returned candidates have transcript overlap greater than 60% (Jaccard similarity) or identical time ranges And previous candidates remain accessible in version history
Exclude Topics/Keywords to Fine-Tune Teasers
Given the user adds one or more exclude terms or phrases When the user regenerates candidates Then returned candidates contain zero case-insensitive occurrences of excluded terms (including stemmed variants) in their transcript captions And excluded terms are visibly listed as active filters and can be removed individually And if no candidates satisfy the filters, the UI reports "No candidates match filters" and offers to relax filters or reset And regeneration with excludes returns results within 20 seconds
Candidate List with Waveform, Transcript Context, and Side-by-Side Compare
Given the review screen shows the candidate list When candidates are displayed Then each candidate shows: confidence score to 2 decimal places, duration, start–end timestamps, mini waveform, and a 5-second pre/post transcript context And selecting two candidates and clicking Compare opens a side-by-side view within 2 seconds And playback in the compare view is synchronized within ±100 ms with linked scrubbing And transcript differences are highlighted for each candidate
Version History with Rollback to Any Prior Candidate
Given the user has generated or approved at least one candidate When a new action occurs (regenerate, approve, apply excludes) Then a version entry is created with timestamp, actor, action type, parameters (e.g., excludes), candidate IDs, and render job IDs And the version history lists entries in reverse chronological order with searchable metadata And clicking Rollback on any entry restores that candidate and settings within 1 second and marks it as the current working version without data loss And rollback actions are themselves recorded as new version entries
Failure Handling and Retries for Render/Update Pipeline
Given a server-side render or player configuration update fails When the failure occurs Then the UI surfaces the error message and job ID within 2 seconds And the system automatically retries up to 2 times with exponential backoff (e.g., 2s, 8s) And if all retries fail, the job is marked Failed with actionable next steps (Retry, Contact Support) and no partial player updates are persisted And re-clicking Approve is idempotent: it does not create duplicate renders or version entries
Embed & Share Controls with Paywall Hook
"As a content business owner, I want to embed teasers on my site and socials with a direct unlock path so that interested viewers can purchase seamlessly."
Description

Generate an embeddable player snippet in “teaser mode” that respects metering and overlays. Support domain allowlists, referrer checks, and disable-download flags. Provide configuration for post-teaser actions (redirect to checkout, open modal, or SSO handoff) and integrations with Stripe/Paddle via webhooks. Propagate UTM parameters through the purchase flow to attribute conversions back to specific teasers.

Acceptance Criteria
Teaser Embed Snippet Generation and Metered Playback
Given a video has Smart Teasers enabled and a 30s preset is selected When the user generates an embed code in teaser mode with CTA overlay enabled Then the returned snippet contains a signed teaser token scoped to the asset and configuration And the player renders the countdown and CTA overlay per configuration And playback is limited to 30.0 ±0.1 seconds of content And seeking beyond the teaser boundary is blocked via UI controls, keyboard shortcuts, and player API calls And teaser end reliably emits a post-teaser action event
Domain Allowlist and Referrer Enforcement
Given an allowlist of example.com and *.partner.io When the embed loads on https://learn.example.com Then playback initializes successfully Given the embed loads on https://unlisted.com When the document.referrer is not on the allowlist Then the player renders a blocked-state message with a configurable support link And no media segment requests are made Given the referrer header is missing When strict referrer enforcement is enabled Then playback is blocked and the decision is logged with reason "no_referrer" And wildcard matching honors subdomains exactly And all allow/deny decisions are logged with timestamp, resolved referrer, and matched rule
Disable Download and Media URL Hardening
Given the teaser embed is loaded Then no download control or direct media URL is present in the DOM or player menu And media is delivered via HLS/DASH using short-lived, signed segment URLs (expiry ≤ 5 minutes) And progressive MP4 endpoints are disabled for teaser requests And right-click context menu on the player surface is disabled And CORS allows only allowed origins and disallows wildcard "*" for credentials And Accept-Ranges is disabled for teaser asset endpoints
Post-Teaser Redirect to Checkout
Given post-teaser action is configured as "redirect" When the teaser ends or the CTA is clicked Then the viewer is redirected within 200 ms to the configured checkout URL And UTM parameters, teaser_id, asset_id, and referrer are appended or preserved on the redirect URL And redirect works for Stripe Checkout and Paddle links in both test and live modes And the action is debounced to prevent multiple redirects from rapid interactions
Post-Teaser Paywall Modal and SSO Handoff
Given post-teaser action is configured as "modal" When the teaser ends Then a paywall modal appears within 150 ms with a purchase CTA and dismiss control And focus is trapped within the modal and is screen-reader accessible Given post-teaser action is configured as "SSO handoff" When the CTA is clicked Then the viewer is redirected to the IdP with a state value containing teaser_id and UTM data And upon successful return an unlock token is provided to the embed And full playback becomes available in the same player without re-embedding
Stripe/Paddle Webhooks and Entitlement Grant
Given a successful payment event (Stripe checkout.session.completed or Paddle transaction.completed) When the webhook is received Then the signature is verified and processing is idempotent And asset_id, teaser_id, and UTM metadata are read from session/transaction metadata And an entitlement or unlock token is created within 3 seconds of receipt And the entitlement enables full playback on subsequent loads or via real-time message to the active embed And unverifiable or failed events do not grant entitlements and are logged with reason
UTM Propagation and Conversion Attribution
Given the embed URL contains UTM parameters and a teaser_id When the viewer is redirected to checkout or opens a paywall modal Then the UTM parameters and teaser_id are persisted in the checkout/session metadata And the same UTM and teaser_id are available on the payment webhook (or resolvable via metadata lookup) And a conversion record is stored linking the payment to the originating teaser_id and UTM set And reporting can query conversions by teaser_id and UTM within the workspace And parameters survive cross-domain redirects without loss or mutation
Teaser Performance Analytics & Attribution
"As a product manager, I want detailed teaser analytics tied to conversions so that I can optimize lengths and messaging for higher ROI."
Description

Capture and report metrics including impressions, play rate, average watch time, completion to boundary, CTA clicks, conversion rate, and revenue attributed. Break down by teaser length, placement, and audience segment. Export to CSV and sync to GA4/Amplitude via events. Respect privacy and consent (GDPR/CCPA), provide IP/user-agent de-duplication, and support experiment labels for A/B comparisons.

Acceptance Criteria
End-to-End Metric Capture and Definitions
- The system records, per teaser_id and per day, the following metrics: impressions, plays, play_rate, avg_watch_time_seconds, completion_to_boundary_rate, cta_clicks, conversions, revenue_attributed. - Impression is counted when the teaser player is rendered in viewport for at least 1 second. - Play is counted when playback reaches at least 1 second. - Play rate equals plays divided by impressions, rounded to two decimals. - Average watch time is computed over plays and reported in seconds with one decimal precision. - Completion to boundary is counted when playback reaches the configured teaser boundary; rate equals completions divided by plays. - CTA clicks are counted only on teaser overlay CTAs rendered within the preview. - Conversion is attributed when a configured conversion event occurs within 24 hours of a play and is attributed to the last teaser played in that window. - Revenue attributed sums the monetary value from attributed conversion events; currency is preserved as provided by the event. - Metrics are available in the analytics UI and API within 5 minutes of the event time with at least 99 percent freshness.
Dimensional Breakdown: Length, Placement, Audience Segment
- Analytics UI and API support filtering and grouping by teaser_length_preset (10s, 30s, custom), placement, and audience_segment. - Grouped reports return each metric per group key and overall totals. - Multiple filters can be applied simultaneously and combine using AND logic. - Custom length teasers display group labels including exact duration in seconds. - Report responses for datasets up to 100k events complete within 3 seconds at the 95th percentile.
GA4 and Amplitude Event Sync
- GA4 events are emitted for teaser_impression, teaser_play, teaser_complete, teaser_cta_click, teaser_conversion with parameters: teaser_id, length_seconds, placement, audience_segment, experiment_id, variant_id, event_id, revenue_value, currency, consent_state. - Amplitude receives equivalent events and properties with userId or deviceId set when available and event_id included for deduplication. - Events are dispatched only when user consent for analytics is true; otherwise events are queued and dropped after 24 hours if consent is not granted. - At least 95 percent of events are delivered to GA4 and Amplitude within 2 minutes; failures are retried up to 3 times with exponential backoff. - Same day event counts between internal analytics and GA4 and Amplitude differ by no more than 3 percent for each event type.
CSV Export of Analytics
- Users can export a selected date range with chosen metrics and dimensions to CSV from the analytics UI and via API. - CSV includes columns: date, teaser_id, teaser_title, length_seconds, placement, audience_segment, experiment_id, variant_id, impressions, plays, play_rate, avg_watch_time_seconds, completion_to_boundary_rate, cta_clicks, conversions, revenue_value, currency. - CSV is UTF-8 encoded, comma-delimited, RFC 4180 compliant, with header row and ISO 8601 UTC timestamps. - Exports up to 1,000,000 rows complete within 60 seconds and are provided via a signed download URL valid for 7 days. - Exported aggregates match UI and API totals for the same filters within 1 percent.
Privacy and Consent Compliance
- No analytics events or third party syncs are emitted before consent under GDPR and CCPA when a consent management platform is present. - For users in EEA, UK, and CPRA regions when geolocated, tracking defaults to consent required until explicit opt in is recorded. - IP addresses are never stored in raw form; only hashed and truncated representations are kept for deduplication. - Users can request access, export, and deletion of analytics data by user identifier; requests are fulfilled within 30 days and actions are auditable. - Data retention is configurable to 90, 180, or 365 days and enforced via automated deletion jobs.
IP and User-Agent De-duplication and Bot Filtering
- Impressions, plays, and CTA clicks are de-duplicated per session using IP_hash plus user_agent plus teaser_id within a 30 minute rolling window. - Event_id is used to enforce idempotency across internal storage, CSV export, and third party syncs. - Known bots and crawlers are excluded using maintained user agent lists and headless detection heuristics. - The analytics UI can toggle between raw and deduplicated counts for validation. - Synthetic replay tests demonstrate at least 95 percent reduction of duplicate counts versus raw events.
Experiment Labels for A/B Comparison
- Teasers can be tagged with experiment_id and variant_id via UI and API; validation prevents empty variant when experiment_id is provided. - Analytics UI and API support filtering, grouping, and side by side comparison by experiment_id and variant_id. - Comparison views compute lift for play_rate, completion_to_boundary_rate, CTA click through rate, conversion rate, and revenue per impression with two decimal precision. - CSV exports and GA4 and Amplitude events include experiment_id and variant_id parameters when present. - When experiment labels are missing or invalid, the system assigns control as the default variant and logs a warning.

Price Ladders

Set per-clip pricing, bundles, and limited-time promos in minutes. Support regional pricing, coupons, and pre-order discounts. A/B test tiers (e.g., $3.99 vs $4.99) and auto-promote winners based on revenue per view—maximizing earnings without guesswork.

Requirements

Per-Clip Pricing Manager
"As a creator, I want to set and update prices for individual clips quickly so that I can tailor pricing to demand and maximize earnings."
Description

Provide creators with a pricing panel to set, preview, and bulk-edit prices for individual clips, with support for default price templates, price floors/ceilings, and validation rules. Enable currency display based on user locale, with clear pre-tax/after-tax indicators as applicable. Expose CRUD operations via API for automation and integrate with the existing catalog so that each generated clip carries an active price record and history. Emit events on price changes for analytics and cache invalidation, and enforce transactional consistency so price at checkout matches the displayed price.

Acceptance Criteria
Set and Preview Single Clip Price
Given I am on a clip's pricing panel and the clip exists in the catalog When I enter a price within the configured floor and ceiling for the account currency and click Save Then the price is saved successfully, respecting currency minor units and precision rules And I see a formatted preview that exactly matches the buyer-facing display for my locale And an active price record is created or updated, and a history entry is appended with previous_value, new_value, currency, actor_id, and timestamp Given I am on the same panel When I enter a price outside the floor/ceiling or with invalid precision Then the save is blocked and an inline error clearly states the allowed range and required precision
Bulk Edit Prices with Floors and Ceilings
Given I have selected multiple clips in the pricing panel When I apply a bulk edit operation (set absolute price, increase/decrease by fixed amount, increase/decrease by percentage) Then the system validates each target price against floors/ceilings and currency precision And any price exceeding boundaries is clamped to the nearest boundary and flagged in the results summary And the operation executes atomically so either all qualifying prices are updated and history is written per clip, or none are if a non-recoverable validation error occurs And the results summary shows counts of updated, clamped, and skipped clips, with reasons for any skips
Default Price Templates for New Clips
Given a default price template is selected for the catalog and is active When a new clip is generated and added to the catalog Then the clip automatically receives an active price derived from the template (including currency), respecting floors/ceilings And a price history entry records template_id, previous_value=null, new_value, currency, actor_id=system, and timestamp Given an editor opens the new clip's pricing panel When they choose to override the template price and save a new value Then the clip's active price updates and the override is recorded in history without changing the global template
Locale Currency and Tax Display
Given my account locale and tax configuration are set and a clip has an active price When the price is displayed in the pricing panel preview and buyer-facing surfaces Then the currency is formatted per locale conventions (symbol/ISO code placement, thousand separators, minor units) using the correct currency for the viewer And a clear indicator shows whether the price is pre-tax or tax-inclusive, according to the account's tax settings and jurisdiction And if the locale is unsupported, the system falls back to a default currency/format and logs a non-blocking warning
Price CRUD API and Validation
Given I have a valid API token with price:write scope When I call POST /prices with clip_id, currency, and amount that meet floors/ceilings and precision Then I receive 201 Created with the price payload, and an active record is set with a matching history entry Given an existing active price When I PATCH /prices/{id} to change amount within bounds Then I receive 200 OK with updated payload, ETag/version incremented, and a history entry appended Given I call GET /prices?clip_id=... When the clip has price history Then I receive 200 OK with current active price and a paginated history list ordered by timestamp desc Given I attempt to set an amount outside bounds or with invalid precision When I POST or PATCH Then I receive 422 Unprocessable Entity with machine-readable error codes (floor_violation, ceiling_violation, precision_violation) Given I call DELETE /prices/{id} When deletion is allowed Then I receive 204 No Content and the active price is unset (or replaced by next valid record), with history noting deleted=true
Price Change Events and Cache Invalidation
Given a price create, update, or delete is successfully committed When the transaction completes Then a price.changed event is published to the analytics/event bus within 2 seconds, including event_id, clip_id, previous_value, new_value, currency, actor_id, change_type, and occurred_at And cache entries for the affected clip price (API and buyer-facing caches) are invalidated or updated within 2 seconds And events are delivered at-least-once with an idempotency key so consumers can de-duplicate And failures to publish are retried with backoff and surfaced to monitoring without rolling back the committed change
Transactional Consistency Between Display and Checkout
Given a buyer initiates checkout from a clip detail page showing a price When the buyer proceeds to payment authorization Then the charged price (before/after tax as configured) equals the price displayed at initiation time And a price snapshot is locked to the checkout session for a configurable TTL to prevent mid-checkout price drift And if the underlying price changes during the session, the snapshot remains unchanged and the order records the snapshot source And automated tests simulate a mid-checkout price update to verify the charged amount matches the snapshot
Bundle Builder & Tiered Pricing
"As a creator, I want to bundle related clips with tiered discounts so that buyers have higher-value options and my average order value increases."
Description

Allow creators to assemble bundles of multiple clips with fixed-price or percentage-discount options, and define tiered offers (e.g., 3 clips for $9.99, 5 for $14.99). Support dynamic bundles based on tags/series and manual curation. Calculate bundle savings, attribute revenue back to constituent clips for reporting, and validate bundle eligibility at checkout. Surface bundles on product pages and search, and ensure compatibility with coupons, regional pricing, and promotions. Handle proration and refunds by proportionally allocating across included clips.

Acceptance Criteria
Manual Bundle Creation — Fixed Price
Given I am a creator with 4 published clips and regional standalone prices set for US When I create a manual bundle selecting those 4 clips and set a fixed bundle price of $14.99 for US and activate it Then the bundle is saved with 4 unique clips, active status, region=US, and price=$14.99 And the computed savings equals (sum of US standalone prices of the 4 clips) − 14.99 and is a non-negative amount And the bundle can be added to cart and priced at $14.99 in US
Dynamic Tag-Based Bundle — Percentage Discount
Given a dynamic bundle rule exists: tag=AI, min=3, max=10, discount=20% off sum of eligible clips, region=US When a buyer in US adds 5 clips tagged AI to their cart Then a dynamic bundle is suggested and a 20% discount is applied to those 5 eligible clips only And if one clip loses the AI tag or becomes unavailable before checkout, the bundle recalculates to remaining eligible clips; if below min, the discount is removed with a clear message
Tiered Offer Auto-Apply at Checkout
Given tiered offers are configured for Series "Neuro101" in US: 3 clips for $9.99, 5 clips for $14.99 When a buyer in US adds 5 eligible "Neuro101" clips to the cart Then the 5-for-$14.99 tier is applied and supersedes the 3-for-$9.99 tier And if the buyer reduces quantity to 3–4 clips, the best applicable tier is applied; if below 3, no tier applies And coupons and promotions, if present, are applied after the tier price in this order: regional base -> tier/bundle -> promotion -> coupon -> rounding
Checkout Eligibility Validation & Error Handling
Given a cart contains a bundle with a duplicate clip, an ineligible clip outside the bundle’s scope, and an expired bundle promotion When the buyer proceeds to checkout Then checkout is blocked and each invalid condition is listed with a reason and a suggested fix (remove duplicate/ineligible clip, update quantity, or remove expired offer) And after resolving issues, totals are recalculated and checkout is allowed without residual bundle discounts
Savings Calculation & Display (Product Page and Search)
Given a clip’s product page is viewed in US and an active bundle includes the clip When the page loads Then the bundle card displays bundle name, US price, savings amount and percentage versus the sum of US standalone prices of included clips, and effective per-clip price And search indexes the bundle with title, tags/series, region availability, active dates, and price; it only appears in search where active for the viewer’s region/date
Revenue Attribution for Bundle Purchases
Given a completed bundle purchase contains clips A, B, C with US standalone prices $6, $3, $1 and bundle net revenue (post-discounts, pre-tax) of $10 When revenue is attributed Then revenue is allocated proportionally by standalone price weights (A=60%, B=30%, C=10%) resulting in allocations A=$6, B=$3, C=$1 And the allocation and input snapshot (region, standalone prices at purchase time, discounts applied, bundle/tier IDs) are stored for reporting
Proration and Refund Allocation
Given a prior bundle purchase with stored clip allocations A=$6, B=$3, C=$1 When a partial refund of $4 is issued Then the refund is allocated proportionally to the stored allocations (A=$2.40, B=$1.20, C=$0.40) and reporting is updated accordingly And when a full refund is issued, all clip allocations are reversed to $0 with corresponding audit records
Regional Pricing & Currency Handling
"As an international buyer, I want to see prices in my local currency with taxes included so that I know exactly what I’ll pay."
Description

Enable regional price rules and currency localization. Allow creators to set regional overrides or rely on automated FX conversion with daily rate updates and psychological rounding (e.g., .99). Determine region primarily via billing address, with IP geolocation fallback and clear user controls to correct region. Display tax-inclusive prices where required (VAT/GST) and ensure compliance messaging. Cache price lookups per region, apply the correct price throughout the funnel, and reconcile settlements in the platform’s base currency. Ensure experiments and promos respect regional constraints.

Acceptance Criteria
Primary Region Resolution with User Correction
Given a buyer has a saved billing address country = DE When they view a clip price Then region = DE is used and the price displays in EUR with German locale formatting Given a buyer has no billing address and their IP geolocates to CA When they view prices Then region = CA is used and the price displays in CAD Given region was inferred from IP When the buyer selects Change region and chooses AU Then all prices refresh to AUD immediately and persist for the session and until billing info changes Given billing country = FR and IP country = US When pricing is determined Then billing country (FR) prevails and a visible Change region control is available
FX Conversion and Psychological Rounding
Given a base USD price of $10.00 and no regional override for JP When the daily FX rate is USD→JPY = 145.20 Then the JP display price equals 10.00 × 145.20 rounded to the nearest .99, resulting in ¥1,449.99 Given a creator sets a regional override price for IN at ₹199.00 When prices are calculated Then ₹199.00 is used instead of any FX conversion Given daily FX rates update at least every 24 hours When the FX updater runs Then converted regional prices refresh within 1 hour and price caches are updated Given the FX provider is temporarily unavailable When conversion is attempted Then the last successful rate not older than 24 hours is used and an alert is logged
Tax-Inclusive Display and Compliance Messaging
Given buyer region is an EU country requiring VAT-inclusive display When prices are shown on product, cart, checkout, and receipt Then amounts are tax-inclusive in EUR and labeled incl. VAT Given buyer region is a US address where sales tax is added at checkout When prices are shown on product and cart Then amounts are pre-tax in USD and checkout displays estimated tax and final total with a separate Tax line item Given buyer region is AU requiring GST-inclusive display When an invoice/receipt is generated Then the total includes GST and a line item shows GST amount with required compliance text
Price Consistency, Caching, and Checkout Locking
Given a buyer in CA When they view the product page, add to cart, proceed to checkout, and complete purchase in one session Then the CAD price is identical across product page, cart, checkout, confirmation, and receipt Given prices are cached per region When an FX rate update or regional override change is published Then only affected region-price cache entries are invalidated within 5 minutes and subsequent fetches use updated prices Given a buyer starts checkout When FX rates update during the checkout session Then the price is locked and does not change for that checkout session Given experiments or promos are active When serving a cached price Then the cache key includes region, experiment bucket, and applicable promo/coupon identifiers to ensure correct pricing
Settlement and Reporting in Base Currency
Given a purchase is captured in EUR for €12.99 When the transaction is settled Then the ledger records base-currency amount using the platform's capture-time FX rate and stores original currency and amount as metadata Given a partial refund is issued for a foreign-currency transaction When reconciliation occurs Then the base-currency refund amount is computed using the original capture rate (or gateway-provided settlement rate) and any rounding adjustment is recorded ≤ 0.01 in base currency Given a payout report includes multi-currency sales When the report is generated Then totals are presented in base currency with line items including original currency, amount, and applied FX rate
Regional Constraints for Experiments and Promotions
Given an A/B price test ($3.99 vs $4.99) is active When buyers in the UK are assigned variants Then assignment and winner auto-promotion are computed using only UK-region revenue per view and exclude data from other regions Given a coupon restricted to AU and NZ When a US buyer attempts to apply the coupon Then the coupon is rejected with a region-specific message Given the same coupon When an AU buyer applies it Then the discount is applied to the AUD price and reflected through checkout and on the receipt Given a limited-time promo configured with AU timezone boundaries When the promo window opens or closes in AU local time Then eligibility updates for AU buyers only and other regions remain unaffected Given a CA-only pre-order discount When the product releases Then CA pricing reverts to the regional rule and receipts for pre-orders show the discount line item
Fallbacks and Unsupported Currency Handling
Given both billing address and IP geolocation are unavailable When prices are shown Then the default Rest of World region and currency are used and a Change region control is visible Given billing country differs from IP country When pricing is applied Then billing country prevails and a non-blocking notice allows the user to switch regions Given a region's local currency is unsupported by the payment gateway When prices are displayed Then a supported fallback currency is used with a clear message before checkout Given a user rapidly changes regions When prices reload Then the displayed region and currency match the latest selection and no stale cached price is shown
Coupons & Promo Codes Engine
"As a creator, I want to issue coupons with limits and expiration so that I can run targeted promotions without eroding margin."
Description

Provide a flexible coupon system supporting percentage and fixed-amount discounts, single-use and multi-use codes, per-user and global redemption limits, start/end times, and eligibility scoping to specific clips or bundles. Implement stacking rules and conflict resolution with other promos, real-time validation at checkout, and clear error/success messaging. Include code generation, import/export, redemption analytics, and an audit log for creation and usage. Ensure secure token formats, rate limiting on attempts, and revocation capabilities.

Acceptance Criteria
Real-Time Coupon Validation at Checkout
Given a cart containing at least one eligible item and a valid percentage coupon, When the user applies the code at checkout, Then the discount equals the eligible-items subtotal multiplied by the coupon percent and rounded to the currency minor unit, applied pre-tax, totals update within 1 second, and a success message displays with the applied code. Given a cart with no eligible items and a valid coupon scoped to other items, When the user applies the code, Then an inline error displays stating the code is not applicable to items in cart and no totals change. Given a fixed-amount coupon whose value exceeds the eligible-items subtotal, When applied, Then the discount caps at the eligible-items subtotal and the order total does not go below zero. Given an invalid, expired, or revoked coupon code, When applied, Then an inline error displays specifying the reason (invalid/expired/revoked), the code entry remains editable, and no discount is applied.
Enforce Single-Use, Multi-Use, Per-User, and Global Limits
Given a single-use coupon that has been redeemed once, When any user attempts to redeem it again, Then redemption is blocked with an error indicating the code has already been used. Given a multi-use coupon with a per-user limit of N and a global limit of G, When a user redeems it N times, Then further attempts by that user are blocked while other users can redeem until the global limit G is reached. Given two simultaneous checkout attempts that would exceed a coupon’s remaining global redemptions, When both submit payment, Then redemptions are applied atomically and at most the remaining allowed redemptions succeed; excess attempts receive a limit-reached error and no discount is granted. Given a checkout that is abandoned or payment fails, When the user had applied a coupon, Then the coupon redemption count does not increment and limits remain unchanged.
Start/End Validity Windows with Timezone Handling
Given a coupon with start_at and end_at timestamps, When evaluated server-side, Then validity uses UTC, is valid at start_at inclusive and invalid at end_at exclusive, and boundary-second tests pass. Given a coupon not yet started, When a user applies it, Then an error displays indicating the coupon starts on <localized_datetime> and no discount is applied. Given a coupon past its end_at, When a user applies it, Then an error displays indicating the coupon has expired and no discount is applied. Given merchant and buyer in different timezones, When messages are shown, Then displayed times are localized to the buyer’s timezone while the stored values remain UTC.
Eligibility Scoping to Clips, Bundles, and Exclusions
Given a coupon scoped to specific clip SKUs, When the cart contains both eligible and ineligible items, Then the discount applies only to eligible line items and is computed per eligible line item. Given a coupon scoped to a bundle SKU, When the cart contains that bundle, Then the discount applies to the bundle total; the same coupon does not apply to individual clips within the bundle unless explicitly configured. Given a coupon with both inclusions and exclusions, When an item appears in both lists, Then the exclusion takes precedence and that item is not discounted. Given a cart with no items matching the coupon scope, When the code is applied, Then an error displays indicating the code is not applicable to current items and no totals change.
Stacking Rules and Conflict Resolution with Other Promotions
Given a non-stackable coupon and an existing automatic promotion, When both are applicable, Then only one promotion is applied—the one that yields the greater customer discount—and a notice explains which promotion was chosen. Given stackable coupons where stacking is allowed by configuration, When both a percentage and a fixed-amount coupon apply, Then percentage discounts are applied to eligible subtotals first, followed by fixed-amount discounts, and the combined discount never exceeds the eligible subtotal. Given two entered coupon codes that cannot be combined, When the second code is applied, Then the system prompts the user to replace the existing code or keep the current one, and applies the chosen state deterministically. Given multiple promos could produce the same final price, When conflict resolution runs, Then the selection is deterministic based on defined tie-breakers (e.g., highest absolute discount, then earliest created), and the decision is logged.
Secure Code Format, Rate Limiting, and Revocation
Given generated coupon codes, When inspected in storage, Then codes are stored hashed (non-reversible) and only a masked form (e.g., last 4 chars) is visible in the UI; plaintext codes are not retrievable after creation or import. Given an attacker attempts to brute-force coupon codes, When more than 10 invalid attempts occur within 1 minute from the same IP or account, Then further attempts are rate-limited for at least 5 minutes and a generic error is returned without confirming existence of codes. Given an active coupon is revoked by an admin, When a user attempts to apply it or complete checkout with it within 60 seconds of revocation, Then application and redemption are blocked with a revoked message and no discount is granted. Given a code was previously applied to a cart, When it is revoked before payment capture, Then the discount is removed at payment time and the user is prompted to review updated totals.
Code Generation, Import/Export, Analytics, and Audit Logging
Given a bulk generation request specifying quantity, prefix, length, discount type/value, limits, scope, validity window, and stacking flag, When executed, Then the system produces that number of unique codes, enforces uniqueness across existing codes, and returns a downloadable CSV with the configured attributes and masked codes. Given an import CSV containing codes and configuration, When processed, Then each row is validated (format, uniqueness, required fields); valid rows are created, duplicates are skipped idempotently using external_id, and a per-row error report is produced for failures. Given an export request for coupon performance, When executed, Then the CSV includes code, status (active/expired/revoked), total redemptions, unique redeemers, gross discount granted, associated revenue, and creation/owner metadata. Given redemptions occur, When viewing analytics, Then counts and amounts reflect only successful payments, are filterable by date range and code, and match underlying transaction data. Given any coupon lifecycle event (create/update/revoke/redeem/failed_redeem), When it occurs, Then an immutable audit log entry is recorded with UTC timestamp, actor (user/service), source IP, code identifier, and payload diff, and is searchable and exportable.
Limited-Time Promotions Scheduler
"As a creator, I want to schedule limited-time discounts with countdowns so that I can drive urgency and conversions while I’m offline."
Description

Allow creators to schedule temporary price changes and flash discounts with precise start/end timestamps (UTC) and timezone-aware display. Automatically apply and roll back prices, show strikethroughs, discount badges, and a countdown timer on storefront and clip pages. Validate overlaps with coupons, bundles, and regional rules; prevent conflicting promos with preflight checks. Trigger webhooks and notifications for lifecycle events, and ensure CDN/cache invalidation so pricing updates are reflected immediately across surfaces.

Acceptance Criteria
UTC Scheduling with Automatic Apply and Rollback
Given a scheduled promotion with start_at and end_at in UTC for specified clips and regions And baseline prices exist for those clips and regions When the system time reaches start_at Then the discounted price is applied to the targeted clips and regions within 5 seconds on storefront, clip pages, and pricing API And CDN/edge caches are invalidated so no stale prices are served after 5 seconds When the system time reaches end_at Then the original baseline price is restored within 5 seconds across the same surfaces And no discounted price is visible before start_at or after end_at
Timezone-Aware Countdown and Display
Given a viewer with a detectable timezone and locale and a scheduled promotion with UTC times When viewing a storefront or clip page before the promotion starts Then a "Starts in" countdown is shown and matches the difference between viewer local time and start_at And the scheduled local start time is displayed using the viewer’s timezone with a UTC fallback label When viewing during the active window Then an "Ends in" countdown is shown that reaches zero exactly at end_at in UTC with no negative values And countdown accuracy is within 1 second across America/Los_Angeles and Asia/Kolkata during DST and non-DST dates
UI Indicators: Strikethrough Price and Discount Badge
Given an active promotion for a clip in a viewer’s region When the clip is displayed on storefront and clip detail pages Then the original price is shown with a strikethrough and the discounted price is prominently displayed in the correct local currency And a discount badge shows the correct percentage or amount off based on the regional baseline price, rounded to the currency’s minor units And indicators are not shown to viewers in regions not targeted by the promotion When the promotion ends Then the strikethrough, discounted price, badge, and countdown are removed within 5 seconds
Preflight Conflict Validation across Coupons, Bundles, and Regional Rules
Given a creator attempts to schedule a promotion with specified clips, regions, discount type, and UTC window When preflight validation runs Then overlapping promotions for the same clip-region window are detected and the request is rejected with HTTP 409 and a list of conflicting promotion IDs and time ranges And interactions with active coupons, bundles, and regional pricing rules are evaluated so that a single deterministic effective price per clip-region is resolved for the entire window And if a deterministic effective price cannot be resolved for any clip-region due to stacking or rule conflicts, the request is rejected with detailed error codes per clip-region And if validation succeeds, an idempotency token is returned and creation with the same token must succeed exactly once
Promotion Lifecycle Webhooks and Notifications
Given webhooks are configured for the creator When a promotion is scheduled, started, updated, canceled, or ended Then a signed webhook is delivered for each event type (promotion.scheduled, promotion.started, promotion.updated, promotion.canceled, promotion.ended) within 10 seconds of the event And the payload includes promo_id, event_type, clip_ids, regions, price_before, price_after, start_at, end_at, and event_timestamp And webhook deliveries use HMAC-SHA256 signatures in X-ClipSpark-Signature and retry up to 5 times with exponential backoff on non-2xx responses And an in-app notification is shown to the creator for started and ended events within 10 seconds
Editing and Canceling Scheduled Promotions with Revalidation and Cache Refresh
Given a scheduled promotion that has not yet started When the creator updates its start_at, end_at, targeted clips/regions, or discount parameters Then preflight validation re-runs and blocks the update if conflicts would arise, otherwise the schedule is updated And all affected surfaces (storefront, clip pages, pricing API) reflect the new schedule within 5 seconds When the creator cancels a scheduled or active promotion Then prices revert to the correct baseline immediately for scheduled, and within 5 seconds for active promotions, and UI indicators are removed And corresponding webhooks (promotion.updated or promotion.canceled) are emitted and caches are invalidated
Pre-Order Discounts & Release Handling
"As a creator, I want to offer discounted pre-orders for unreleased clips so that I can gauge demand and earn early revenue."
Description

Support listing unreleased clips for pre-order at an early-bird price with clear release dates. Offer configurable payment flows (authorize-and-capture on release or immediate capture) and automatic access unlock plus notifications upon release. Integrate with coupons and promos under defined stacking policies, and handle edge cases such as failed captures and refunds. Display pre-order status in checkout and receipts, and ensure content remains inaccessible until release while preserving the promotional price.

Acceptance Criteria
Pre-Order Product Page Visibility & Gating
Given an unreleased clip configured for pre-order with base price B, early-bird price P, release timestamp T, and region R with currency C When a shopper in region R views the clip page before T Then the page displays a "Pre-order" badge And the price shown equals P in currency C with the base price B visually de-emphasized if configured And the release date/time T is displayed localized to the shopper’s timezone with a countdown And full content playback and downloads are blocked; only optional trailers or previews (if configured) are playable And the primary call-to-action reads "Pre-order"
Checkout and Receipt Pre-Order Status & Price Preservation
Given the shopper proceeds to checkout with a pre-order line item priced at P for a clip releasing at T When the checkout page is rendered Then the line item clearly shows "Pre-order", the price P, and the release date/time T localized to the shopper And the selected payment flow ("Authorize at pre-order, capture on release" or "Charge immediately") is displayed When the order is placed Then the confirmation page and receipt show "Pre-order", price P, release date/time T, and the selected payment flow And the order history preserves price P and "Pre-order" status regardless of any subsequent price changes
Payment Flow: Authorize at Pre-Order, Capture on Release
Given the store is configured for "Authorize at pre-order, capture on release" and the clip is in pre-order state with price P and release time T When the shopper places a pre-order with a payment method supporting authorization Then an authorization is created for P plus applicable taxes/fees and no funds are captured before T And the authorization expiration is validated against T And if the authorization would expire before T, the shopper is notified at least 72 hours before expiration to re-authorize; failure to re-authorize cancels the pre-order before expiration When time reaches T Then the system attempts capture within 5 minutes; on success, the order status changes to "Paid", and access is unlocked
Payment Flow: Immediate Capture with Delayed Access
Given the store is configured for "Charge immediately" and the clip is in pre-order state with price P and release time T When the shopper places a pre-order Then the payment of P plus applicable taxes/fees is captured immediately And the order status becomes "Paid — Pre-order" And access to the full content remains locked until T despite successful payment
Release Automation: Access Unlock and Notifications
Given one or more pre-ordered clips with release time T and eligible orders When system time reaches T Then access is unlocked for all orders that are "Paid" or successfully captured within 5 minutes of T And email and in-app notifications are sent to purchasers within 5 minutes of access unlock containing links to the clip And the clip’s status changes from "Pre-order" to "Released" in the storefront and library
Coupons, Promos, Stacking, and Regional Pricing
Given a pre-order with base regional price B_R in currency C_R, pre-order discount D, and optional coupon or promo When the shopper applies discounts Then the system enforces stacking policy And if stacking is allowed, final price P_final = (B_R - D) with additional coupon or promo applied per policy without going below zero And if stacking is disallowed, the best single discount is applied (lower resulting price prevails) And taxes and currency reflect region R; the final payable amount is shown in C_R And the receipt records all applied discounts and the final price P_final
Exception Handling: Failed Captures and Refunds
Given a pre-order with release time T When a capture attempt at or after T fails for an authorized order Then access is not unlocked And the system retries up to 3 times over 48 hours and notifies the shopper after each failure with instructions to update payment And after the final failed attempt, the pre-order is cancelled and marked "Payment Failed — Pre-order Cancelled" When a shopper requests cancellation or refund before T Then a full refund is issued if previously captured, access remains locked, and the order is marked "Refunded — Pre-order Cancelled" When a refund is processed after T per policy Then access is revoked within 5 minutes, notifications are sent, and receipts and ledgers reflect the refund
Price A/B Testing & Auto-Promotion
"As a creator, I want to A/B test price tiers and automatically adopt the best performer so that I can maximize revenue without manual analysis."
Description

Provide an experimentation framework to test multiple price points per clip or bundle. Randomize and persist user bucketing, with stratification by region and traffic source. Track key metrics (conversion rate, revenue per view, ARPU) and enforce minimum sample sizes and statistical significance before declaring a winner. Automatically roll out the winning price with guardrails (max delta, minimum margin), support scheduled experiment windows, and offer a one-click rollback. Include real-time dashboards, exports, and event streams for analytics.

Acceptance Criteria
Randomized and Persistent Bucketing by Region and Traffic Source
Given an active price experiment with variants and configured strata for region and traffic source And a new user arrives with region and traffic source detected When the user is eligible for the experiment window Then the user is assigned to a variant uniformly at random within their stratum with allocation ratios as configured (±2% tolerance after 10,000 assignments per stratum) And the assignment is persisted to the user account ID (or a durable cookie if anonymous) with a 90-day TTL And on subsequent sessions and pages the same variant is shown consistently unless the assignment is explicitly invalidated by config change And users on an exclusion list (e.g., internal IPs, test accounts) are never bucketed
Metric Collection and Attribution per Variant and Stratum
Given an active price experiment with defined events (impression, click, purchase) When a user views a priced clip or bundle Then an impression event is recorded with timestamp, user/anon ID, clip/bundle ID, variant ID, region, traffic source, and price When the user clicks through to checkout Then a click event is recorded with the same identifiers When the user completes payment Then a purchase event is recorded including revenue amount, currency, discount, cost inputs for margin, and order ID And conversion rate, revenue per view (RPV), ARPU, and gross margin are computed per variant overall and per (region x source) stratum And metrics are visible in the dashboard and exportable with a maximum data freshness lag of 2 minutes
Statistical Significance and Minimum Sample Enforcement
Given an experiment with configured minimum sample size per variant per stratum (e.g., 1,000 impressions and 100 purchases) and a 95% confidence threshold When metrics are computed during the experiment Then the system does not declare a winner until minimum samples are met for all active variants in at least one target stratum and overall And significance is tested using a two-tailed test appropriate to the metric (e.g., proportion test for conversion, t-test or bootstrap for RPV/ARPU) And the dashboard clearly labels current p-values, confidence intervals, and whether guardrails are satisfied And any early-peek requests display a warning and do not trigger auto-promotion
Auto-Promotion with Guardrails (Max Delta and Minimum Margin)
Given an experiment reaches the configured significance threshold and minimum samples And the leading variant satisfies guardrails: price change from control ≤ max delta and projected gross margin ≥ minimum margin When auto-promotion is enabled Then within 10 minutes all new eligible users receive the winning price as the default (outside experiment) And previously bucketed users retain their assignment unless an "override on promote" flag is enabled And promotion is logged with timestamp, actor=system, prior and new price, and guardrail values And if guardrails are not met, the system does not promote and surfaces a "manual review required" status
Scheduled Experiment Windows and Traffic Handling at Boundaries
Given an experiment with a startAt and endAt time in UTC When current time is before startAt Then no users are bucketed and control pricing is shown When current time is within [startAt, endAt] Then eligible users are bucketed and see their assigned variant When current time is after endAt Then no new users are bucketed and existing assignments are honored for 24 hours (grace period) unless the experiment is explicitly stopped And late-arriving events are attributed to the experiment if their timestamps fall within the window or grace period
One-Click Rollback of Promoted Price
Given a price was auto-promoted or manually promoted from an experiment When an authorized user clicks "Rollback" in the experiment dashboard and confirms Then the system restores the prior price configuration for the affected clips/bundles within 60 seconds And new users immediately see the restored price, while existing checkouts complete with the price they started with And the rollback action is audit-logged (who, when, before/after values, reason) And experiment data and assignments remain intact for analysis
Real-Time Dashboard, CSV Export, and Event Stream
Given an active or completed experiment When viewing the dashboard Then metrics (impressions, clicks, purchases, conversion, RPV, ARPU, margin, p-values, CI) are displayed per variant and per stratum with data freshness ≤ 2 minutes When exporting results Then a CSV is generated within 30 seconds containing row-level aggregates by day, variant, region, and traffic source with a documented schema When enabling the event stream Then purchase and attribution events are emitted to the configured webhook within 5 seconds of occurrence with retries (up to 5 attempts with exponential backoff) and signature verification

Subscriber Pass

Offer monthly or annual access with entitlements to specific creators, collections, or all drops. Trials, proration, and pause options are built-in via Stripe. Seamless upgrades and save-offers reduce churn while viewers unlock new drops automatically—creating predictable recurring revenue.

Requirements

Stripe Checkout & Billing Integration
"As a viewer, I want a simple and secure checkout to buy a pass so that I can start watching subscriber-only drops without friction."
Description

Implement a secure, PCI-compliant Stripe Checkout and Billing integration to sell Subscriber Passes on monthly and annual cadences. Create and manage Stripe Customers and Subscriptions, store Stripe IDs in ClipSpark, and support SCA/3DS flows. Ensure error handling for payment failures and a retry strategy. Map each subscription to an internal entitlement scope for access control. Provide localized pricing display, tax settings via Stripe, and receipts delivery. This serves as the transactional backbone for purchasing and maintaining access to creators, collections, or all drops.

Acceptance Criteria
Checkout creates Customer + Subscription (SCA/3DS supported)
Given a signed-in user selects a monthly or annual Subscriber Pass When the backend creates a Stripe Checkout session (mode=subscription) using the price_id for the selected cadence and entitlement scope Then the user is redirected to Stripe Checkout with localized amount and applicable tax displayed And if SCA/3DS is required, authentication is completed within Checkout before confirmation And on success, Stripe creates a Customer and Subscription (status active or trialing) And ClipSpark stores stripe_customer_id, stripe_subscription_id, stripe_price_id, stripe_product_id, default_payment_method_id, latest_invoice_id within 5 seconds of webhook confirmation And no raw card data is transmitted to or stored by ClipSpark servers And on cancel/failure, the user returns to the cancel URL and no subscription record is persisted in ClipSpark
Webhook lifecycle sync and entitlement mapping
Given Stripe sends a valid webhook (checkout.session.completed, customer.subscription.created|updated|deleted, invoice.paid, invoice.payment_failed) When the webhook signature is verified and the event is processed idempotently Then ClipSpark updates the subscription record, invoice status, next_renewal, and stores event_id for audit And ClipSpark maps the subscription to an entitlement scope (creator|collection|all) via Stripe product/price metadata And access to matching drops is granted within 60 seconds for active/trialing and revoked within 60 seconds for canceled/unpaid/past_due beyond grace And newly published drops matching the entitlement scope are accessible without additional purchase And all changes are logged with timestamp, event type, and outcome
Payment failure handling and retry strategy
Given an invoice payment fails for an active subscription When Stripe initiates up to 3 retry attempts over 7 days and emits invoice.payment_failed and customer.subscription.updated events Then ClipSpark sets the subscription to grace state and maintains access until payment succeeds or retries are exhausted And on successful retry, status returns to active and next_renewal is updated; on final failure, subscription is canceled and access is revoked immediately And the user is notified via Stripe email and an in-app banner within 5 minutes of each failure event And all state transitions are recorded with reason and source
Localized pricing and currency display
Given a visitor’s locale and currency are detected via Accept-Language and geolocation When viewing the pricing page and initiating Checkout Then prices are displayed in the visitor’s currency if a corresponding Stripe Price exists; otherwise USD is shown as fallback And number/currency formatting matches the visitor’s locale And the price_id used to create the Checkout session matches the displayed currency and cadence And the tax inclusion/exclusion label aligns with Stripe tax settings for that price
Tax calculation and compliance via Stripe
Given Stripe Tax or tax rates are configured When a buyer supplies billing address and (optionally) a tax ID in Checkout Then Stripe computes and displays applicable taxes before confirmation And tax amounts and jurisdiction details are stored on the invoice and accessible via hosted_invoice_url And tax-exempt buyers with valid tax IDs are not charged tax And ClipSpark stores customer tax_exempt status and default tax location on the customer record
Receipts delivery and invoice access
Given an initial or renewal invoice is paid When Stripe finalizes the invoice (status=paid) Then Stripe emails a payment receipt to the customer’s email And ClipSpark saves hosted_invoice_url and invoice_pdf link on the subscription within 60 seconds And the user can view/download the latest invoice from My Billing in ClipSpark And no receipt is sent for failed payments
Plan changes with proration and entitlement updates
Given an active subscriber requests a plan change (monthly ↔ annual) or entitlement scope change When the Stripe Subscription is updated with proration enabled Then Stripe generates proration credits/charges and invoices accordingly (immediate or next cycle per configuration) And ClipSpark updates stripe_price_id, stripe_product_id, next_renewal, and entitlement scope within 60 seconds of webhook confirmation And the user’s access reflects the new scope immediately after update And only one active Subscriber Pass subscription exists per user
Plan Catalog & Scoped Pass Definitions
"As a product admin, I want to configure subscription plans tied to creators, collections, or all content so that buyers receive the correct level of access automatically."
Description

Define a plan catalog that models Creator Pass, Collection Pass, and All-Access Pass, each with monthly and annual price points. Associate each plan with one or more entitlement scopes (creator IDs, collection IDs, or global) and ensure consistent plan IDs between Stripe Products/Prices and ClipSpark. Include the ability to mark plans as trial-eligible and to attach promotional metadata (e.g., save-offers). Provide configuration and validation to prevent conflicting scopes and to guarantee predictable access rules across the product.

Acceptance Criteria
Create All Pass Types with Monthly and Annual Price Points
Given I am an admin with access to Stripe and ClipSpark plan APIs And passType is one of Creator, Collection, or AllAccess And a Stripe Product exists with two Prices for monthly and annual billing When I create a plan with both monthlyPriceId and annualPriceId that reference the same Stripe Product Then the plan is created with a unique planId, the specified passType, and both billing periods And retrieving the plan returns both price points with correct currency and amount And creating a plan missing either monthly or annual price is rejected with 422 PLAN_PRICEPOINTS_REQUIRED
Associate Entitlement Scopes by Pass Type with Conflict Validation
Given passType=Creator When I supply creatorIds [A,B] and no collectionIds and global=false Then the plan is valid and saved Given passType=Collection When I supply collectionIds [C] and no creatorIds and global=false Then the plan is valid and saved Given passType=AllAccess When I set global=true and leave creatorIds and collectionIds empty Then the plan is valid and saved When any plan includes both creatorIds and collectionIds or sets global=true alongside any IDs Then the request is rejected with 422 SCOPE_CONFLICT and no plan is created
Enforce Consistent Plan and Stripe IDs
Given a Stripe Product exists with id prod_123 and Prices price_monthly and price_annual that belong to prod_123 When I create a plan referencing prod_123 with monthlyPriceId=price_monthly and annualPriceId=price_annual Then plan.planId equals prod_123 And plan.price.monthly.stripePriceId equals price_monthly And plan.price.annual.stripePriceId equals price_annual And if a provided Price does not belong to the Product, the request is rejected with 422 PRICE_PRODUCT_MISMATCH And if a plan already exists for prod_123, creating another plan for the same Product is rejected with 409 PLAN_ALREADY_EXISTS
Configure Trial-Eligible Plans and Trial Durations
Given a plan is created with trialEligible=true and trialDays=14 When the plan is persisted Then trialEligible=true and trialDays=14 are stored and returned via API And both monthly and annual Stripe Prices are configured with trial_period_days=14 When trialEligible=true and trialDays is missing or outside 1..30 Then the request is rejected with 422 INVALID_TRIAL_CONFIGURATION
Attach and Validate Promotional Metadata (Save-Offers)
Given I include promotionalMetadata.saveOfferPercent=20 and promotionalMetadata.saveOfferCopy="Save 20% annually" and valid startAt and endAt timestamps When the plan is created Then the promotional metadata is stored and returned unchanged And saveOfferPercent must be an integer between 0 and 100 inclusive; otherwise 422 INVALID_PROMO_PERCENT And saveOfferCopy must be 120 characters or fewer; otherwise 422 INVALID_PROMO_COPY And endAt must be after startAt; otherwise 422 INVALID_PROMO_WINDOW
Enforce Predictable Access Rules from Entitlement Scopes
Given a subscriber purchases a Creator Pass scoped to creatorIds [A,B] When the subscription is activated Then the subscriber can access all existing and future drops by creators A and B within 60 seconds of publish time And the subscriber cannot access drops by any other creators or collections Given a subscriber purchases a Collection Pass scoped to collectionIds [X] Then access is limited to drops in collection X only, regardless of creator Given a subscriber purchases an All-Access Pass Then the subscriber can access all drops platform-wide
Prevent Scope Changes After Activation (Immutability)
Given a plan has at least one active subscription When an admin attempts to update passType, creatorIds, collectionIds, or global fields Then the request is rejected with 409 PLAN_SCOPE_IMMUTABLE And adding or rotating Stripe Price IDs for the same billing periods is allowed and does not alter entitlements
Entitlement Engine & Auto-Unlock
"As a subscriber, I want new drops from my subscribed creators to unlock automatically so that I don’t have to manage access or miss fresh content."
Description

Build an entitlement service that evaluates a user’s active subscriptions and grants access to eligible drops (videos, highlights, captions, summaries) based on scope and status. Enforce access checks on APIs and UI, with low-latency caching and graceful fallbacks. Automatically grant entitlement to newly published drops within subscribed creators/collections without manual updates. Support edge cases such as paused subscriptions, trial states, grace periods, and failed payment dunning, keeping access consistent and auditable.

Acceptance Criteria
Auto-Unlock: New Drop Under Subscribed Creator
Given a user has an active, in-good-standing subscription scoped to Creator A When Creator A publishes a new drop Then within 60 seconds the entitlement for that drop evaluates to access=true via API GET /drops/{dropId}/entitlement (200, {"access":true,"scope":"creator"}) and the UI renders the drop as unlocked And the drop appears in the user’s New feed within 60 seconds with access=true And no manual admin action is required to grant access
Access Enforcement: Out-of-Scope Drop
Given a user’s subscription is scoped to Collection X only When the user requests a drop not in Collection X via API GET /drops/{dropId}/entitlement Then the service responds 403 with code "ENTITLEMENT_DENIED" and reason "scope_mismatch" and the UI renders a locked state with an Upgrade CTA And only non-sensitive metadata (title, thumbnail, duration) is visible; captions, full text, downloadable assets, and highlight playback remain inaccessible
Trials, Grace Period, and Dunning Consistency
Given a user is in trialing status for a subscription scoped to Creator A When the user requests any drop under Creator A Then entitlement returns access=true via API and the UI shows unlocked When the trial ends without conversion and a configured gracePeriodEndAt is set Then access remains true until gracePeriodEndAt and flips to access=false within 5 minutes after that timestamp When payment enters dunning and is resolved before gracePeriodEndAt Then access remains uninterrupted; when dunning fails beyond gracePeriodEndAt, access is revoked and API returns 403 with code "PAYMENT_REQUIRED"
Pause/Resume Subscription Behavior
Given a user with an active subscription triggers a pause When the pause takes effect Then all entitlements under that subscription are revoked within 5 minutes and API returns 403 with code "SUBSCRIPTION_PAUSED" and the UI indicates "Subscription paused" When the user resumes the subscription Then prior in-scope entitlements are restored within 5 minutes without requiring re-login and new drops auto-unlock as normal And audit logs for both transitions include subscriptionId, previousStatus, newStatus, and effectiveAt
Upgrade/Downgrade Proration & Recalculation
Given a user upgrades from Creator A to All-Access mid-cycle When Stripe confirms the upgrade event Then the entitlement engine grants access to all creators/collections within 60 seconds, API returns scope="all_access", and no previously accessible drops are lost; billing reflects a proration event id Given a user schedules a downgrade from All-Access to Creator A Then entitlements remain at all_access scope until periodEndAt and reduce to creator scope within 5 minutes after periodEndAt; newly published drops outside Creator A after periodEndAt evaluate to access=false And user-specific cache entries are invalidated or updated within 60 seconds on both upgrade and downgrade
Decision Auditability & Traceability
Given any entitlement evaluation request Then a decision log entry is written within 2 seconds containing requestId, userId, resourceId, decision (grant|deny), scope, reasonCodes, subscriptionId(s), evaluationSource (cache|db), and timestamp Given an admin queries GET /entitlements/logs?userId={id}&since={t} Then logs are retrievable for at least 365 days and can be filtered by decision and scope; ≥99.9% of evaluations have a corresponding log entry When a user requests an audit export for the last 90 days Then a CSV or JSON export is generated within 60 seconds and its entries match stored decisions
Performance, Caching, and Graceful Fallback
Given warm cache conditions When evaluating entitlements via API Then p95 latency ≤ 150 ms and cache hit rate ≥ 80% over a rolling 24 hours Given a cache miss Then database fallback completes with p95 ≤ 500 ms and returns a correct decision; cache is populated asynchronously Given a cache outage Then the service uses database-only mode with a circuit breaker, returns correct decisions (0 false-positive grants), and maintains p99 ≤ 800 ms; no user receives a 5xx due solely to cache unavailability for more than 1 minute When subscription state changes (activate, pause, resume, cancel, upgrade, downgrade) Then relevant cache keys are invalidated or updated within 60 seconds
Real-time Access Sync via Stripe Webhooks
"As a platform operator, I want subscription changes from Stripe to update user access instantly so that viewers experience accurate, real-time access without support intervention."
Description

Process Stripe webhooks (e.g., subscription created/updated/canceled, payment succeeded/failed, customer updated) to keep ClipSpark entitlements in sync in near real time. Verify signatures, ensure idempotency, queue events for reliability, and implement retries with dead-letter handling. Update local state promptly to reflect upgrades, downgrades, pauses, proration changes, and trial conversions. Provide monitoring, alerting, and audit logs for operational visibility and compliance.

Acceptance Criteria
Webhook Signature Verification and Security
Given a Stripe webhook request with a valid Stripe-Signature header and shared secret When the endpoint receives the request Then the endpoint returns HTTP 2xx and enqueues the event for processing. Given a request with a missing or invalid Stripe-Signature header When received Then the endpoint returns HTTP 400 and no event is enqueued and no state is mutated. Given a request with a timestamp outside the configured tolerance window (300 seconds) When received Then the endpoint returns HTTP 400 and no state change occurs. Given any rejected request When rejected Then an audit log entry is recorded with reason and correlation ID and no PII beyond Stripe’s event.id is stored. Given the webhook endpoint is accessed over HTTP When attempted Then the connection is refused or redirected to HTTPS and the request is not processed.
Idempotent Event Processing
Given a previously processed Stripe event (by event.id) When the same event is redelivered one or more times Then side effects are applied exactly once and subsequent deliveries return HTTP 2xx with no-op processing. Given concurrent deliveries of the same event.id When processed Then only one execution acquires the lock and performs side effects while others exit without mutation. Given an event that updates an object older than the current local state When processed Then the processor fetches the latest object from Stripe and applies only forward-moving changes; stale updates are ignored and logged.
Durable Queue, Retry, and Dead-letter Handling
Given a valid webhook event When accepted Then it is persisted to a durable queue and acknowledged within 2 seconds. Given a transient processing failure (e.g., network timeout to Stripe) When dequeued Then the event is retried with exponential backoff up to 6 attempts over 30 minutes. Given retries are exhausted or a permanent error is detected (e.g., schema mismatch) When processing fails Then the event is moved to a dead-letter queue within 1 minute and an alert is emitted. Given a dead-lettered event is manually requeued When retried Then it passes through the standard pipeline and idempotency rules apply.
Subscription Lifecycle Entitlement Sync
Given customer.subscription.created for a known customer with valid price-to-entitlement mapping When processed Then ClipSpark entitlements are granted within 60 seconds and linked to the correct user. Given customer.subscription.updated that adds or removes subscription items effective immediately When processed Then corresponding entitlements are added or removed within 60 seconds. Given customer.subscription.deleted or updated with cancel_at_period_end=false When processed Then access is revoked within 60 seconds. Given a cancellation with cancel_at_period_end=true When processed Then access remains until current_period_end and is revoked within 60 seconds after that time. Given customer.updated changes the customer's email When processed Then the associated ClipSpark user email is updated without altering entitlements.
Trial and Proration Handling
Given a subscription created with status=trialing When processed Then trial entitlements are granted within 60 seconds and marked as trial. Given a trial converts to paid (invoice.paid or subscription status transitions to active) When processed Then entitlements persist and the trial flag is removed within 60 seconds. Given a trial is shortened or extended (trial_end changes) When processed Then access start/end dates are updated within 60 seconds to match the new trial_end. Given a mid-cycle upgrade with proration When the update event and subsequent invoice.paid are processed Then higher-tier entitlements are granted within 60 seconds of invoice.paid. Given a scheduled downgrade effective at period end When processed Then higher-tier entitlements remain until current_period_end and are removed within 60 seconds afterward.
Pause, Resume, Upgrade, and Downgrade Access Effects
Given a subscription is paused (pause_collection active) When processed Then all entitlements are suspended within 60 seconds and user access is blocked while preserving state. Given a subscription resumes from pause When processed Then prior entitlements are restored within 60 seconds. Given an immediate upgrade (effective immediately) When processed Then new entitlements are granted within 60 seconds. Given a downgrade scheduled for next period When processed Then higher-tier entitlements are retained until the effective date and removed within 60 seconds after.
Monitoring, Alerting, and Audit Logging
Given normal processing When running Then metrics are emitted for events_received, events_processed_success, processing_latency_ms, retry_count, and dlq_count and are visible on the monitoring dashboard. Given the error rate exceeds 5% for 5 consecutive minutes or DLQ count > 0 When detected Then an alert is sent to on-call within 2 minutes containing top error types and last event.id. Given any event is processed (success or failure) When completed Then an immutable audit log entry is written with event.id, event.type, stripe object IDs, action taken, outcome, and timestamp and is queryable within 1 minute. Given a rejected webhook (invalid signature or schema) When rejected Then an audit log entry with reason is recorded and no entitlements are changed.
Upgrade/Downgrade & Save-Offer Flows
"As a subscriber, I want to switch plans or accept a save-offer during cancelation so that I can adjust cost without losing access I still value."
Description

Create in-app flows to seamlessly change scope (creator → all-access, collection ↔ creator, monthly ↔ annual) with accurate proration previews and effective dates. Implement a cancelation flow with contextual save-offers (discount, pause, or downgrade) and track reasons and outcomes for churn analysis. Ensure no access gaps or over-entitlements during plan transitions and reflect changes consistently in UI and APIs. Log events for analytics to measure conversion and churn-save performance.

Acceptance Criteria
Upgrade: Creator Pass to All-Access with Proration Preview
Given a subscriber on an active Creator Pass with a valid payment method And a Stripe proration quote is available for an immediate upgrade to All-Access When the user opens the Upgrade flow and selects All-Access Then the UI displays an itemized proration preview (base price, unused time credit, taxes, discounts) with currency code and 2-decimal precision And the preview shows total due now, new renewal amount, and effective_at in local time and UTC And the API endpoint GET /subscriptions/{id}/upgrade-quote returns amounts and effective_at matching the UI When the user confirms the upgrade Then the payment is successfully captured and the subscription plan is updated to All-Access with effective_at as shown And All-Access entitlements unlock across web and API within 60 seconds without access gaps And previously available drops remain accessible during the transition (no over/under-entitlement) And a receipt is issued and visible in Billing history And events subscription_upgrade_requested and subscription_upgrade_succeeded are emitted with fields: user_id, subscription_id, previous_plan_id, new_plan_id, quote_id, amount, currency, effective_at, proration_amount, discount_code If the payment fails Then no plan change occurs, entitlements remain unchanged, the UI shows a retryable error, and event subscription_upgrade_failed is emitted with error_code
Downgrade: All-Access to Single Creator at End of Term
Given a subscriber on an active All-Access plan When the user selects Downgrade to a specific Creator effective at end of current term Then the UI shows: target creator, effective_at = current_period_end, next renewal amount, and a summary of access that will be lost And no immediate charge or credit is applied (end-of-term downgrade) And the API PATCH /subscriptions/{id} creates a pending_change with {type:"downgrade", target_plan_id, effective_at} Until effective_at the subscriber retains All-Access entitlements At effective_at + 60 seconds, access to non-selected creators' drops is revoked; API returns 403 for removed content and UI shows "Upgrade to access" And events subscription_downgrade_scheduled and subscription_downgrade_effective are emitted with previous_plan_id, new_plan_id, effective_at If the user cancels the pending change before effective_at Then pending_change is removed and entitlements remain All-Access
Change Billing Cadence: Monthly to Annual with Accurate Proration
Given a subscriber on a Monthly plan When the user selects switch to Annual and chooses "Start now" Then the UI shows an itemized immediate charge with proration credit for unused days, applied discounts, taxes, the new renewal date (+12 months), and total due now with currency at 2-decimal precision And the amounts match the Stripe quote returned from GET /subscriptions/{id}/change-cadence-quote When the user confirms Then the immediate charge succeeds, the plan cadence is Annual, and there is no interruption to entitlements And the next invoice is scheduled on the new annual renewal date If the user selects "Start at end of term" Then no immediate charge occurs, a pending_change with effective_at = current_period_end is created, and the UI/API reflect the scheduled change If payment fails on "Start now" Then no cadence change occurs, the UI shows a retryable error, and event subscription_cadence_change_failed is emitted
Cancelation Flow with Contextual Save-Offers and Reason Capture
Given a subscriber initiates the cancelation flow When the save-offer evaluation runs Then up to three ranked offers are presented (discount, pause, downgrade) with clear impact on price, access, and next billing date When the subscriber selects an offer Then the corresponding subscription update is applied (coupon apply, pause schedule, or downgrade schedule) and a confirmation state is shown with updated effective_at/next_renewal And events save_offer_viewed and save_offer_selected are emitted with offer_type, offer_value, accepted=true If the subscriber continues to cancel Then a reason must be selected from a predefined list (with optional free-text) before confirmation And on confirmation, the subscription is set to cancel at end of term (paid) or immediately (trial/unpaid) and effective_at is displayed And entitlements end at effective_at + 60 seconds; UI and API deny access thereafter And events subscription_cancel_started and subscription_canceled are emitted with reason_code, reason_text, effective_at, outcome If an offer is declined Then event save_offer_declined is emitted with offer_type and accepted=false
Pause Subscription and Auto-Resume Behavior
Given a subscriber chooses Pause from manage billing or the cancelation flow When the user selects a pause duration of 1, 2, or 3 months and confirms Then the UI shows pause_start and resume_at, and a Paused status is visible on the subscription And the Stripe subscription is updated to pause_collection with resume_at set; no invoices are generated during the pause At pause_start + 60 seconds, subscriber-only drops are locked across UI and API; listings indicate locked state At resume_at + 60 seconds, entitlements are restored automatically and the next invoice is scheduled per plan cadence When the user selects Resume early Then the pause is removed, billing resumes per Stripe rules, and access is restored within 60 seconds And events subscription_paused, subscription_resumed are emitted with pause_start, resume_at, actor
UI and API Consistency During Pending Plan Transitions
Given a subscription with a scheduled upgrade, downgrade, pause, or cadence change When GET /subscriptions/{id} is called Then the response includes current_plan, state="pending_change", pending_change {type, target_plan_id, effective_at}, and a proration summary where applicable And the dashboard shows a banner with the same effective_at (localized) and an Undo action if allowed Within 60 seconds after effective_at, the API reflects the new plan and pending_change is cleared, and the UI updates accordingly across sessions and devices Repeated POST/PATCH requests with the same Idempotency-Key do not create duplicate transitions or charges If two conflicting transitions are requested within 60 seconds, the later request supersedes and the user sees the final state consistently in UI and API Access controls never expose over-entitlements during the transition window
Analytics Event Logging for Conversion and Churn-Save Performance
Given any upgrade, downgrade, cadence change, pause/resume, or cancelation action When the action is initiated, succeeds, or fails Then analytics events are emitted with schema fields: event_name, user_id, subscription_id, previous_plan_id, new_plan_id, action, effective_at, amount, currency, proration_amount, discount_code, offer_type, reason_code, outcome, idempotency_key, ts And events are delivered at-least-once, deduplicated by idempotency_key, and ordered by ts within a session And events are queryable in the analytics dashboard within 5 minutes for 95% of cases And no PII beyond user_id is included; GDPR consent is respected (events dropped when consent=false) And event volumes and failure rates are monitored with alerts on error_rate > 1% over 5-minute windows
Trials, Proration, and Pause/Resume Controls
"As a new viewer, I want a trial and clear cost changes when I modify my plan so that I can evaluate the service and manage spending confidently."
Description

Support free trials with configurable durations and eligibility rules (e.g., one per account), and schedule trial-to-paid conversions via Stripe. Enable proration for mid-cycle changes with clear cost previews. Implement pause/resume controls that immediately affect billing and access per policy, including pause time limits and automatic resume handling. Notify users via email in key moments (trial ending, payment failure, paused expiring) to reduce churn and confusion.

Acceptance Criteria
Single-Use Trial Eligibility Enforcement
Rule: A user may consume at most one free trial per configured scope (per_plan or per_product). Given plan P has trial_duration_days=14 and trial_scope="per_plan" When account A without prior trial on P starts a trial Then a trial is created immediately with end_at = now + 14 days, conversion_at scheduled at end_at, and entitlements for P are granted during the trial. Given account A has previously consumed a trial on P (any state: completed, canceled, or converted) When A attempts to start another trial on P Then the request is blocked with message "Trial already used" and a path to subscribe without trial is offered. Given trial_scope="per_product" across plans P1 and P2 And A has consumed a trial on P1 When A attempts to start a trial on P2 Then the request is blocked as above. And all trial start/deny events are audit-logged with account_id, plan_id, scope, and timestamp.
Scheduled Trial-to-Paid Conversion and Access Switching
Given an active trial for plan P ending at T and a valid default payment method on file When the clock reaches T Then the subscription converts to paid within 60 seconds, the charge equals plan price minus active discounts/taxes as applicable, next_billing_at = T + billing_interval, and entitlements continue without interruption. Given an active trial ending at T and no valid payment method or a charge failure occurs at T When conversion is attempted Then premium entitlements are revoked immediately, a payment-failed email is sent within 5 minutes with a secure update-payment link, and conversion is retried per retry policy. And a "trial_ending_soon" email is sent at T-72h (and again at T-24h if unpaid) containing plan name, price, conversion time in the user’s timezone, and cancel/manage links.
Mid-Cycle Upgrade Proration with Accurate Cost Preview
Given a monthly subscription to Plan A at $20 started at cycle_start S with 30-day cycles And at S+10d the user chooses to upgrade immediately to Plan B at $30 When viewing the confirmation screen Then a cost preview displays: credit_for_unused_A = $20 * (20/30) = $13.34, charge_for_remaining_B = $30 * (20/30) = $20.00, net_due_now = $6.66 (±$0.01), taxes/fees itemized, and next_billing_at remains S+30d. When the user confirms Then access to Plan B entitlements is granted within 60 seconds and the final invoice matches the preview total within $0.01. And all amounts and dates are shown in the user’s currency and timezone.
Mid-Cycle Downgrade Proration with Immediate Credit or End-of-Cycle Option
Rule: Downgrades support two effective times: immediate_with_proration or end_of_cycle. Given a monthly subscription to Plan B at $30 with 15/30 days remaining When the user selects immediate_with_proration to downgrade to Plan A at $20 Then a preview shows immediate credit = ($30 * 15/30) - ($20 * 15/30) = $5.00 applied to the customer balance, access changes to Plan A within 60 seconds, and next_billing_at stays unchanged. Given the same scenario When the user selects end_of_cycle Then the preview shows $0 due now, no credits issued, access remains Plan B until next_billing_at, and the plan changes at next_billing_at automatically. And the issued credit appears on the next invoice and is reflected in the account balance within 60 seconds.
Pause Subscription with Immediate Effects and Enforced Limits
Given pause_limit_days=30 and pause_policy=immediate When a user pauses their subscription now for 15 days Then premium entitlements are revoked within 60 seconds, next_billing_at is extended by 15 days, no invoices are generated during the pause, and a confirmation email is sent immediately. When the user attempts to pause for 45 days Then the request is rejected with an error referencing the 30-day maximum. And only one active pause is allowed; attempting to create a second pause while paused is blocked. And the UI shows paused_until and a Resume Now action.
Automatic Resume and Early Resume Handling
Given a subscription paused_until=R with a valid payment method When current_time reaches R Then the subscription resumes within 60 minutes, premium entitlements are restored, next_billing_at is recalculated to account for the paused duration, and a resume confirmation email is sent. Given the same paused subscription When the user clicks Resume Now before R Then the subscription resumes within 60 seconds, access is restored immediately, and billing resumes according to the recalculated next_billing_at. Given resume requires a payment attempt and the payment fails When resume is triggered automatically or manually Then access remains suspended, a payment-failed email is sent within 5 minutes with a secure update-payment link, and retries follow the configured policy.
Lifecycle Notifications: Trial Ending, Payment Failure, Pause Expiring
Rule: Key lifecycle emails must be timely, actionable, and tracked. Given an active trial ending at T When time is T-72h (and again at T-24h if still unpaid) Then send a trial ending email containing plan name, price, conversion timestamp in user’s timezone, manage payment and cancel links, and message_id for tracking. Given any invoice payment fails When the failure occurs Then send a payment failure email within 5 minutes including amount, reason if available, next retry time, and a secure link to update payment (3DS if required). Given a paused subscription with paused_until=R When time is R-48h Then send a pause expiring email with the resume date/time and link to extend pause if remaining allowance exists; otherwise show guidance to adjust billing. And all emails respect user locale, are deduplicated to 1 per event, and unsubscribe preferences are honored where legally applicable.
Subscriber Self-Serve Portal
"As a subscriber, I want to manage my subscription and payment details on my own so that I can make changes quickly without support tickets."
Description

Provide a secure self-serve area for subscribers to manage their pass: view status and renewal date, update payment method, upgrade/downgrade, pause/resume, cancel, and view invoices. Integrate either Stripe Customer Portal or a custom UI backed by Stripe APIs, ensuring consistent entitlements and SCA handling. Include session security, responsive design, and accessibility standards so users can manage subscriptions across devices without contacting support.

Acceptance Criteria
View Subscription Status and Renewal Date
- Given an authenticated subscriber, when they open the self-serve portal dashboard, then the portal displays plan name, billing interval (monthly/annual), current status (active/paused/canceled/in_trial), and the relevant date: next renewal date/time (active), trial end date/time (in_trial), or access end date/time (canceled) in the user’s local timezone. - And the displayed values match the Stripe subscription/customer record (status, plan, current_period_end, trial_end) for the user within 60 seconds of the latest change (via realtime fetch or webhook sync). - And for canceled subscriptions, no renewal date is shown; instead an "Access until <date/time>" message is displayed. - And the dashboard subscription card renders with complete data within 2.0 seconds at the 95th percentile on a 10 Mbps connection.
Update Payment Method with SCA
- Given an authenticated subscriber with a valid session, when they choose "Update payment method," then the flow uses Stripe Elements/Customer Portal and never exposes raw PAN data to ClipSpark servers (only Stripe tokens/IDs are exchanged). - When the card requires SCA (3DS), then the SCA challenge is presented and, upon success, the new payment method becomes the default on the Stripe customer and subscription within 10 seconds. - If SCA fails or is canceled, then the prior default payment method remains unchanged and a clear error state is shown with a retry option. - If there is an outstanding invoice in requires_action state, then after successful SCA the invoice is paid and its status updates to paid within 60 seconds, and the portal reflects the cleared balance. - On success, the user sees a confirmation message and email receipt from Stripe (if enabled) within 5 minutes.
Upgrade/Downgrade with Proration and Entitlements Update
- Given an active subscription, when the user selects a new plan in the same product family, then a price preview shows: immediate proration charge/credit (amount and currency), tax, and next invoice amount before confirmation. - When upgrading, then the change applies immediately upon confirmation, Stripe subscription updates to the new price, and a proration invoice is created/paid per Stripe settings; the portal shows success within 10 seconds. - When downgrading, then the change is scheduled for the period end by default and is clearly labeled with the effective date/time; if the user chooses "Apply now," immediate proration credit is applied per Stripe rules and is shown pre-confirmation. - After any plan change, then ClipSpark entitlements adjust to the new plan (creators/collections/all drops) within 60 seconds of the Stripe event, and newly eligible drops are unlocked automatically; previously accessible content removed by downgrade is no longer accessible on next entitlement check. - All monetary values displayed match Stripe’s preview/ resulting invoice totals (±$0.01 tolerance due to rounding).
Manage Subscription Status: Pause, Resume, and Cancel with Save Offer
- Given an active subscription, when the user selects Pause, then the subscription is paused in Stripe (collection paused) immediately upon confirmation, the portal status changes to Paused, and subscription-based entitlements are suspended within 60 seconds; previously purchased one-off content remains accessible. - When resuming from Paused, then billing resumes on the next cycle per Stripe settings, portal status changes to Active, and entitlements are restored within 60 seconds. - When the user initiates Cancel, then a save offer is presented (e.g., X% discount for N cycles or Pause instead); if accepted, the corresponding coupon or pause is applied in Stripe and the portal confirms the updated status within 10 seconds. - If the user declines the save offer and confirms Cancel, then the subscription is set to cancel at period end by default (with an explicit option to cancel immediately), the portal displays the final access date/time, and entitlements remain until end-of-term (or are removed immediately if immediate cancel is chosen). - A confirmation email is sent for pause, resume, and cancel actions (if enabled in Stripe), and portal activity is logged with timestamp and actor.
Invoice History View and Download
- Given an authenticated subscriber, when they open Billing History, then the portal lists all invoices for the Stripe customer for at least the past 24 months with date, invoice number, status (paid/open/void/uncollected), subtotal, tax, total, and currency. - When the user selects Download on any invoice, then a PDF downloads successfully and its totals, line items, tax, and currency match the corresponding Stripe invoice. - Open or uncollectible invoices display a Pay or Retry SCA action when applicable; after successful payment or SCA, status updates to paid within 60 seconds. - The list supports pagination for accounts with >50 invoices and returns results within 2.0 seconds at p95. - Amounts shown in the portal match Stripe values (±$0.01 tolerance) and all timestamps are shown in the user’s local timezone.
Responsive Design and Accessibility Compliance
- The self-serve portal is fully usable at 320px, 768px, and 1280px widths without horizontal scrolling for core flows (status, payment method, plan change, pause/resume/cancel, invoices). - All interactive elements have a minimum touch target size of 44x44 px on mobile and are keyboard-accessible with visible focus states; focus order is logical for all dialogs and forms. - Color contrast meets WCAG 2.2 AA (≥4.5:1 for text; ≥3:1 for large text and UI components). - All form fields, buttons, and alerts have accessible names/labels and ARIA roles where appropriate; error messages are programmatically associated with fields. - Automated accessibility scan (axe or equivalent) shows 0 critical violations on the portal’s primary flows, and manual screen reader checks (NVDA/VoiceOver) confirm actionable labels on key controls.
Session Security and Access Control
- Access to the self-serve portal requires an authenticated ClipSpark account mapped to a Stripe customer; unauthenticated access redirects to sign-in. - User sessions expire after 30 minutes of inactivity; upon expiry, any action redirects to sign-in and no sensitive data is displayed. - For Stripe Customer Portal, sessions are created server-side with an allowlisted return URL and expire if not used within 60 seconds; users cannot access another customer’s portal link (verified by receiving 403 on tampered session IDs). - For a custom UI, all write operations (payment method updates, plan changes, pause/resume/cancel) are performed via server-side Stripe API calls protected by CSRF tokens and user authorization; client never holds secret keys. - Security logs record portal logins and subscription changes with user ID, action, and timestamp; rate limiting applies to sensitive endpoints (e.g., 10 actions/min per user) without impacting normal usage.

Paywall Insights

Track the full funnel from preview start to purchase: tease-to-buy rate, drop-off timestamps, post-purchase retention heatmaps, and revenue by clip or pack. Attribute sales by channel and affiliate, and get prescriptive tips (e.g., extend preview by 5s) to lift conversion.

Requirements

End-to-End Paywall Funnel Tracking
"As a content seller, I want a clear funnel from preview start to purchase so that I can identify where viewers drop off and prioritize improvements that increase conversion."
Description

Implement event-level tracking across the paywall journey from preview start to purchase completion, including preview start/end, paywall view, checkout start, purchase success/failure, and refunds. Sessionize visitor interactions, deduplicate users across devices when possible, and compute key metrics such as tease-to-buy rate, step conversion rates, time-to-purchase distributions, and per-asset funnel performance. Provide filters for date range, clip or pack, channel, campaign, device, and affiliate. Visualize funnels and trends in-product with drill-down to individual sessions while honoring privacy and consent settings. Store events with durable, queryable schemas and retention policies aligned with compliance and cost. Integrate with ClipSpark’s player SDK to emit reliable preview and progress events and with billing to reconcile purchases and refunds.

Acceptance Criteria
Reliable Player SDK Event Tracking
Given a viewer interacts with a preview-enabled asset in the ClipSpark player and analytics consent = true When preview starts, pauses/resumes, ends; the paywall is viewed; checkout starts; a purchase succeeds or fails; and a refund is issued Then the SDK emits events: preview_start, preview_progress, preview_end, paywall_view, checkout_start, purchase_success, purchase_failure, refund with fields: event_id (UUIDv4), event_type, asset_id, asset_type (clip|pack), session_id, user_id or anonymous_id, timestamp_ms_utc, playback_ms_offset, device, os, browser, channel, campaign, affiliate, consent_state And events are delivered to the backend within 2 seconds P95 and 5 seconds P99 And duplicate events are deduplicated server-side by event_id (idempotent upsert) And if offline, events queue locally (max 10,000 events or 72 hours) and retry with exponential backoff; dropped events are surfaced in SDK diagnostics And when consent = false, non-essential analytics events are suppressed or anonymized per policy; no persistent identifiers beyond anonymous session are stored
Robust Sessionization and User Deduplication
Given a visitor generates events across web and mobile for one or more assets When events are ingested and processed Then events are grouped into sessions that end after 30 minutes of inactivity or immediately upon purchase_success, whichever occurs first And cross-device dedup links to a unified user_id when the same authenticated account is used or a signed cross-device token matches; otherwise anonymous_id is preserved And session_id and user_id are stable and unique; session fragmentation rate <= 1% on fixture datasets And cross-device linkage achieves false-positive rate <= 0.1% and false-negative rate <= 5% on test suites And attribution metadata (channel, campaign, affiliate) is persisted at session and event level using last non-direct touch within 7-day lookback unless a signed override is present
Accurate Funnel Metrics Calculation
Given a selected date range and any combination of filters (asset, channel, campaign, device, affiliate) When the system computes funnel metrics Then definitions are applied: Tease-to-buy rate = distinct purchasers / distinct previewers for the same asset; Step conversion rates = unique users advancing from preview_start -> paywall_view -> checkout_start -> purchase_success; Time-to-purchase distribution = P50/P75/P90 and histogram in minutes from first preview to purchase; Per-asset funnel and revenue are computed And purchase_failure and refunds are incorporated: net revenue = gross - refunds; purchasers exclude fully refunded users when "Net" is selected And results match synthetic fixture datasets within 0.5% absolute error across all metrics And incremental updates reflect new/late events within 2 minutes end-to-end P95 (up to 7 days lateness supported via backfill) And computed metrics are timezone-consistent (workspace-local) and reproducible given the same inputs
Segmentation Filters Apply Consistently
Given a user applies filters for date range, asset (clip or pack), channel, campaign, device, and affiliate When filters are added, combined, modified, or cleared Then all widgets (funnel, trends, revenue, heatmaps, tables) reflect the same filtered cohort And filters persist in the URL so views are shareable and reloadable; invalid tokens fall back to safe defaults and are logged And default date range is last 30 days; empty and zero-data states are shown with clear messaging And P95 dashboard refresh time after any filter change is <= 3 seconds for up to 10M events And filter interactions are debounced to avoid over-querying and are accessible via keyboard navigation
In-Product Visualization and Drill-Down
Given the Paywall Insights dashboard is loaded with any set of filters When the user reviews charts and tables Then the UI shows: step funnel with counts and rates; trends for previewers, paywall views, checkouts, purchases, and net revenue; post-purchase retention heatmap (days 0–30); per-asset and per-channel tables with sorting and CSV export And clicking any step or table row drills down to a paginated sessions list within 2 clicks; each session opens an event timeline with playback timestamps, steps taken, device, and attribution And personally identifiable information is masked or withheld in drill-down unless consent scope=analytics is granted; opt-outs are enforced at query time And visualizations render correctly on desktop and mobile; color contrast and focus states meet WCAG 2.1 AA And P95 time to first render <= 2 seconds and to open a session timeline <= 1.5 seconds on datasets up to 10M events
Billing and Refund Reconciliation
Given purchases and refunds occur via the billing provider When webhooks are received and nightly sync jobs run Then purchase_success and refund records are upserted idempotently keyed by transaction_id and customer_id And amounts, currency, taxes, discounts, and partial/full refund flags are captured and joined to sessions And reconciliation verifies dashboard net revenue equals billing net revenue per day, per asset, and per channel within 0.1%; discrepancies trigger an alert and an automated replay job And chargebacks are reflected as refund events within 24 hours of notification and adjust metrics accordingly And attribution present at checkout (channel, campaign, affiliate) is preserved on the purchase and used in downstream metrics
Data Storage, Schema, and Retention Compliance
Given paywall-related events are ingested into the analytics store When events are persisted and queried Then the event schema is versioned (schema_version), documented, and backward-compatible; indexes support queries by date, asset_id, user_id, session_id, and channel And ingestion provides at-least-once delivery; queries achieve exactly-once semantics via event_id deduplication And storage durability meets >= 11 nines; standard dashboard queries complete in <= 1.5 seconds P95 on 10M events And raw events are retained 13 months; hourly/daily aggregates retained 24 months; retention is configurable per workspace and applied automatically And privacy requests (erasure/export) are fulfilled within 30 days; anonymization removes direct identifiers from raw and aggregates; consent changes are respected in future queries
Drop-off Timestamp Analytics
"As a creator, I want to see exactly when viewers stop watching the preview so that I can adjust the teaser length and content to keep them engaged through the paywall."
Description

Capture second-by-second preview viewability and exit events to identify precise timestamps where viewers abandon. Compute cumulative completion curves, per-second retention, and top loss moments for each clip or pack. Surface annotated charts that overlay drop-offs with transcript segments and detected highlights from ClipSpark, enabling creators to see which moments cause exits. Enable segmentation by channel, affiliate, device, geography, and traffic source. Provide CSV export and links to relevant session replays (if available). Respect sample-size thresholds to avoid misleading insights and exclude internal or test traffic by rules.

Acceptance Criteria
Second-by-Second Viewability and Exit Capture
Given a preview play event starts When playback reaches each elapsed second Then a viewability record is stored for that second with fields: clip_id/pack_id, session_id, second_index (int), is_visible (boolean), and event_timestamp (UTC) Given a viewer exits or navigates away When the exit occurs Then an exit event is stored with second_index matching the last fully visible second and exit_reason set appropriately (close, navigate, idle-timeout) Given seek, pause, background tab, or buffering occurs When a second is not actually shown to the viewer Then no viewability record is stored for that second and gaps are allowed Given a session plays less than 1 second When analytics are computed Then the session is excluded from per-second retention and counted under subsecond_plays Given supported browsers (latest Chrome, Safari, Firefox, Edge) on desktop and mobile When preview is watched Then capture rate is ≥ 98% of actually viewed seconds with clock drift < 100ms relative to player time
Completion Curves and Top Loss Moments Computation
Given recorded per-second viewability and exits for a clip or pack When analytics are computed hourly Then per-second retention (%) = viewers who reached second s / total starts and a cumulative completion curve is generated for each second from 0 to duration Given a clip or pack has at least 100 valid sessions (configurable per workspace) When analytics run Then top loss moments (max 5) are identified as seconds with the highest exit delta over a 3-second window and sorted by impact (largest to smallest) Given an administrator triggers recomputation for a time range When recompute completes Then metrics match a control query within ±0.1 percentage points on a validation dataset and recompute status is logged Given variable clip durations When curves are rendered Then axes are normalized to seconds from start (x) and 0–100% (y) with no missing or duplicate seconds
Annotated Drop-off Chart with Transcript and Highlights Overlay
Given a clip has transcript segments and ClipSpark-detected highlights aligned by timestamps When the drop-off chart is opened Then transcript segments render as bands and highlight markers appear at their start times on the same timeline as the retention curve Given a user hovers over a drop-off spike When the tooltip appears Then it shows second_index, retention_pct, exit_count, transcript excerpt (<= 200 chars), and highlight label if within ±2 seconds Given the user clicks a transcript segment or highlight marker When clicked Then the preview player seeks to the corresponding timestamp within ±0.2 seconds and begins playback Given a clip lacks transcript and/or highlights When the chart loads Then the missing layer(s) display a "No data" legend without errors and the retention curve still renders
Segmentation by Channel, Affiliate, Device, Geography, and Traffic Source
Given filter controls for channel, affiliate, device, geography (country), and traffic source When a single or combined filter is applied Then charts, top loss moments, and KPIs update to the filtered cohort within 2 seconds for datasets under 1M sessions Given a saved segment is selected When applied Then the filter chips reflect all dimensions and the URL query encodes the selection for shareable links Given filters are cleared When the reset action is triggered Then results revert to All Traffic and totals match the unfiltered dataset within ±0.1% Given a country is selected When filters apply Then only sessions with that country code are included across all computations
CSV Export of Retention and Drop-off Data
Given the current view and applied filters When the user clicks Export CSV Then a CSV is generated within 10 seconds containing columns: clip_id, pack_id, second_index, viewers_started, viewers_reached, retention_pct, exits, channel, affiliate, device, country, traffic_source, report_generated_at (UTC) Given the export would exceed 10 million rows When export is requested Then the export runs asynchronously, shows job progress, and emails a download link on completion within 24 hours Given exclusion rules for internal/test traffic When export completes Then excluded sessions are absent from the CSV and totals match on-screen KPIs within ±0.1% Given numeric typing requirements When the CSV is downloaded Then numeric fields are unformatted numbers and retention_pct is rounded to 2 decimals without a % symbol
Session Replay Linking
Given a session has an available replay from the integrated provider When the user selects a drop-off spike at second s Then a Session Replay link is displayed that opens the replay at timestamp s±1s in a new tab Given a session lacks an available replay When the user inspects details Then the UI shows "Replay unavailable" and no link is rendered Given the current user lacks replay permissions per org policy When viewing analytics Then replay links are hidden and an access message is displayed without exposing PII Given the replay provider returns an error (HTTP 4xx/5xx) When the link is clicked Then the error is surfaced with a retry option and analytics UI remains responsive
Sample Size Thresholds and Traffic Exclusion Rules
Given the filtered cohort has fewer than the configured minimum valid preview starts (default 100) When the chart is rendered Then retention curves and top loss moments are replaced by an Insufficient data state and prescriptive tips are suppressed Given internal/test traffic identification rules (IP ranges, staff flags, test UA, UTM test tags) When analytics are computed Then matching sessions are excluded from charts, KPIs, and exports Given an admin updates thresholds or exclusion rules When changes are saved Then they take effect within 15 minutes and are recorded with versioning and audit metadata Given the environment is non-production (staging) When analytics load Then thresholds can be bypassed for QA but the UI shows a Non-production watermark
Post-Purchase Retention Heatmaps
"As a product marketer, I want heatmaps of buyer engagement after purchase so that I can learn which sections deliver value and use those insights to craft better previews and upsells."
Description

Generate post-purchase watch heatmaps that visualize where buyers spend time, rewatch, and drop off within purchased clips or packs. Aggregate viewer progress into normalized heatmaps per asset and cohort (e.g., first-time buyers, affiliates, channels). Show average watch time, completion rates, and rewatch hotspots aligned to transcript and highlights. Provide smoothing and normalization controls to handle differing clip durations and audiences. Integrate directly into ClipSpark’s player and asset pages for quick inspection. Enforce privacy by aggregating and thresholding counts and allow customers to opt out as required.

Acceptance Criteria
Post‑Purchase Heatmap Generation per Asset
Given a purchased clip or pack asset with analytics enabled and ≥10 unique purchasers in scope When the heatmap computation job runs (scheduled hourly) or an on‑demand recompute is triggered by an admin Then a post‑purchase watch heatmap is generated per asset using default binning of 1% of duration (min 0.5s, max 5s) And rewatch hotspots are flagged where a bin’s watch time is ≥1.5× the median of its 10 neighboring bins And average watch time (seconds) and completion rate (%) are computed from purchaser views only and displayed above the heatmap And for packs, an aggregated pack‑level normalized heatmap is produced alongside per‑clip heatmaps
Cohort‑Based Heatmaps and Metrics
Given a cohort filter with options [All purchasers, First‑time buyers, Returning buyers, Affiliate=<value>, Channel=<value>] When a cohort is selected (or multiple filters are combined) Then the heatmap, hotspots, average watch time, completion rate, and counts recompute using only events from purchasers in the selected cohort(s) And the UI reflects the active cohort(s) and updates within ≤1.5 seconds for assets with ≤1M events And clearing filters restores the default All purchasers view
Player and Asset Page Integration
Given a purchased asset’s page is opened in ClipSpark When the player loads Then a retention heatmap overlay appears on the scrub bar with a toggle labeled "Retention Heatmap" defaulted to On And hovering a bin shows a tooltip with timestamp, bin intensity, watch time (s), unique purchasers contributing (if ≥ privacy threshold), and completion % at that point And clicking a bin seeks playback to the bin’s start time within ≤200 ms of user action And on pack pages, users can switch between per‑clip heatmaps and an aggregated pack view within the same module
Transcript and Highlights Alignment
Given the asset has an aligned transcript and highlight clips When a user hovers a hotspot region on the heatmap Then the corresponding transcript lines within the region are highlighted and the relevant highlight chips are emphasized And clicking a transcript line scrolls/positions the player to that timestamp and highlights the corresponding heatmap bin And if a transcript is unavailable, alignment affordances are hidden while the heatmap remains functional
Privacy Thresholding and Opt‑Out Compliance
Given an organization privacy threshold K=10 and a list of purchasers who have opted out of analytics When fewer than K unique purchasers exist in the current cohort for an asset Then the heatmap visualization and detailed tooltips are suppressed and a message "Insufficient data to display aggregated retention" is shown And opted‑out purchasers’ events are excluded from all calculations and exports And no user‑level identifiers are stored or displayed; only aggregated bin metrics that meet or exceed K are exposed via UI and API
Smoothing and Normalization Controls
Given smoothing and normalization controls are available in the heatmap module When a user selects Smoothing = Off/Low/Medium/High Then a moving‑average window of 0/3/5/9 bins is applied to the visualization without altering underlying metrics (avg watch time, completion) And when the user toggles Scale = Raw counts | Normalized (%) Then Raw displays absolute watch time per bin, while Normalized resamples to 100 bins across the asset’s duration for cross‑asset comparability And the last‑used settings persist per user and workspace
Data Freshness and Backfill
Given watch events are emitted during post‑purchase playback When events are ingested Then the heatmap updates within 15 minutes and displays a "Last updated" timestamp And failed computations are retried up to 3 times with exponential backoff and errors are logged for observability And duplicate rapid‑seek pings within a 2‑second window do not inflate bin counts
Revenue Attribution & Cohort Reporting
"As a business owner, I want revenue tied to specific clips, packs, channels, and affiliates so that I can invest in what performs and cut spend where it doesn’t."
Description

Attribute revenue to clips and packs as well as to channels, campaigns, and affiliates using UTM parameters, referral codes, and coupon/affiliate IDs. Support configurable attribution models (last-click default, first-click, linear) and handle edge cases such as refunds, chargebacks, multi-currency normalization, and partial pack purchases. Produce cohort reports that tie conversion and revenue to acquisition source and preview behavior, enabling LTV, ARPU, and conversion-by-source comparisons. Present per-asset and per-source revenue breakdowns with drill-through to underlying orders. Sync with billing and affiliate systems for accurate reconciliation.

Acceptance Criteria
Default Last-Click Attribution Using UTMs, Referral Codes, and Affiliate IDs
Given an order has multiple tracked touches with UTMs, referral code, and/or affiliate coupon, When applying the default attribution model, Then 100% of the order’s net revenue is attributed to the most recent qualifying touch prior to purchase, And source resolution priority is affiliate/coupon ID > referral code > UTM parameters > Direct. Given a purchase with no UTMs, referral, or affiliate, When attribution runs, Then the source is set to Direct and 100% of revenue is attributed to Direct. Given touches occur across multiple devices linked to the same user identity, When attribution runs, Then last-click selection is evaluated across all linked devices within the identity graph. Given the order contains revenue by clip and/or pack, When attribution runs, Then per-asset revenue inherits the same source attribution as the order and rolls up to per-source and per-asset breakdowns.
Configurable First-Click and Linear Attribution Models
Given the workspace attribution model is set to First-Click, When an order has N qualifying touches, Then 100% of net revenue is attributed to the earliest qualifying touch, And totals across sources equal the order revenue. Given the workspace attribution model is set to Linear, When an order has N qualifying touches, Then revenue is split equally 1/N per touch rounded to 2 decimals, And any rounding remainder is assigned to the latest touch, And the sum of attributed revenue equals the order net revenue. Given the user changes the selected attribution model in reporting, When metrics reload, Then all attribution-based charts and tables recompute within 60 seconds, And totals remain consistent with underlying orders.
Multi-Currency Normalization and Display
Given an order is captured in currency C≠USD, When normalization runs, Then normalized_revenue_usd = captured_amount_c * FX_rate_at_capture_timestamp, And the FX source and timestamp are stored, And both native currency and USD-normalized values are displayed. Given a refund or chargeback in currency C, When normalization runs, Then the negative normalized value uses the FX rate at the original capture timestamp unless an authoritative FX at refund timestamp is required by policy, And rounding is to 2 decimals with bankers rounding, And totals reconcile to native currency movements. Given a report is filtered by USD, When data renders, Then sorting, totals, and cohorts use normalized USD values consistently.
Refunds, Partial Refunds, and Chargebacks Adjust Attribution
Given a full refund occurs for an attributed order, When reconciliation processes the refund, Then the previously attributed revenue is reversed (negative) against the same source(s) per the model, And cohort LTV/ARPU update within 15 minutes. Given a partial refund occurs for a multi-item order, When reconciliation runs, Then only the refunded items’ attributed revenue are reversed proportionally by item net value and original attribution shares. Given a chargeback is posted, When reconciliation runs, Then the order’s attributed revenue is removed (negative) and flagged as chargeback in drill-through, And reversal propagates to per-asset, per-source, and cohort metrics. Given a refund is canceled, When reconciliation runs, Then the attribution reversal is undone and metrics return to pre-refund values.
Partial Pack Purchases and Discount Proration to Clips
Given a pack contains M clips and the customer purchases a subset S (S≤M), When revenue is allocated, Then only the purchased clips receive revenue attribution, And pack-level discounts/coupons are prorated to items by list-price weight before attribution. Given a coupon applies only to a subset of items, When allocation runs, Then discounted amounts reduce those items’ net revenue only, And attributed revenue reflects the reduced net values. Given per-asset reporting is viewed, When data loads, Then per-clip totals equal the sum of allocated item net revenue and match the order’s itemization after proration.
Cohort Reporting by Acquisition Source and Preview Behavior
Given cohorts are defined by first preview-start source within a selected time window, When rendering cohort tables, Then each user appears in exactly one cohort keyed by acquisition source, And preview drop-off percentiles (e.g., 25%, 50%, 75%) are stored per user-session. Given cohort metrics are calculated, When results render, Then conversion rate, ARPU, and LTV are computed per cohort and per attribution model, And values reconcile to underlying orders and user counts. Given filters for date range, asset (clip/pack), and channel are applied, When the report refreshes, Then cohort rows and charts reflect the filters, And totals equal the filtered order set, And refresh completes within 60 seconds.
Per-Asset/Source Drill-Through and External Reconciliation Sync
Given a user clicks a revenue total in a per-source or per-asset report, When drill-through opens, Then it lists underlying orders with order_id, timestamp, gross, fees, net, currency, normalized_usd, attribution details, refund/chargeback status, and links to the asset and customer. Given drill-through results are summed, When compared to the parent aggregate, Then the totals match exactly within 2 decimal places. Given billing and affiliate systems emit events (e.g., Stripe charge.succeeded/refunded, affiliate sale), When the sync job runs, Then events are ingested idempotently using external IDs, deduplicated, and applied within 10 minutes, With retries using exponential backoff up to 24 hours, And any failed events are visible in an error queue with reason and next retry time. Given a manual reconciliation is triggered for a date range, When the job completes, Then counts and totals in ClipSpark match billing and affiliate system reports for that period within defined tolerance (≤0.1%).
Prescriptive Conversion Tips
"As a seller, I want clear, evidence-backed tips to improve my paywall conversion so that I can make high-impact changes without deep analytics expertise."
Description

Deliver actionable, context-aware recommendations that improve conversion, such as extending preview length, repositioning highlights earlier, or adding captions at high-drop moments. Combine rules derived from benchmarks with model-driven pattern detection on funnel and drop-off data to estimate potential lift and confidence. Display tips inline within analytics views, link to supporting evidence (charts and timestamps), and enable one-click tasks to implement changes in ClipSpark (e.g., adjust preview window, promote highlight). Track acceptance and outcome to learn which suggestions work and refine future recommendations.

Acceptance Criteria
Inline Tips Display in Paywall Insights
Given a user opens the Paywall Insights view for an asset with eligible data When the page renders Then a Tips panel appears showing up to 5 tips sorted by highest estimated lift first And each tip shows: an actionable title (imperative verb), a one-sentence rationale citing the metric and timestamp/segment, an estimated lift range (e.g., +3–7%), a confidence percentage badge, and at least one evidence link And tips respect the current segment filter (channel/affiliate) and refresh within 2 seconds of filter change And if no eligible tips exist, a "No tips yet — collecting more data" empty state is shown with a Learn More link And duplicate or semantically identical tips for the same action/asset/segment are deduplicated so only one appears And each tip displays Apply and Dismiss controls, with Apply disabled for users without edit permission and a tooltip explaining why
Tip Generation Eligibility and Latency
Given an asset has at least 100 preview starts and 20 purchases in the last 14 days And retention or funnel analysis identifies a drop-off increase ≥10% within any 10-second window When nightly aggregation completes or new data crosses thresholds Then eligible tips are generated and available in the UI within 30 minutes And each generated tip includes fields: tip_id, action_type, segment (channel/affiliate), timestamps referenced, estimated_lift_low/high, confidence_pct, and evidence_refs And tips with confidence <60% or sample sizes below thresholds are not shown to end users And a tip will not be regenerated for the same action/asset/segment within a 30-day cooldown unless data shifts by ≥10% absolute in the affected metric
One-Click Apply: Adjust Preview Length
Given a tip recommends extending the preview by N seconds where 1 ≤ N ≤ 15 And the user has edit permission When the user clicks Apply on the tip Then the asset's preview end time increases by N seconds without exceeding the video duration And the change is reflected in the preview player within 5 seconds And an audit log entry is created with actor, previous_value, new_value, tip_id, and timestamp And the tip status changes to Applied and a success toast is shown with an Undo option valid for 2 minutes And if the change cannot be applied (e.g., max duration reached), a clear error is shown and no changes are persisted
One-Click Apply: Promote Highlight Earlier
Given a tip recommends promoting a specific highlight earlier to precede the first major drop-off And the suggested new start time is within the video bounds and maintains minimum clip duration ≥5 seconds When the user clicks Apply Then the highlight's in/out timestamps are updated to the suggested bounds with ±0.5s tolerance And if the move would overlap another highlight, the system auto-resolves by shifting order without reducing any highlight below 5 seconds, or presents a non-blocking conflict notice with a View in Editor link And the updated highlight order is visible in the editor and any pack listing within 10 seconds And an analytics annotation is added referencing tip_id and change details
One-Click Apply: Add Captions at High-Drop Segments
Given a tip recommends adding captions at one or more high-drop timestamps And the asset lacks captions or has gaps covering those timestamps When the user clicks Apply Then a caption generation job is queued for the specified segments and completes within 10 minutes for videos ≤60 minutes And generated captions align to speech with average word timing error ≤300ms on those segments And captions are attached to the preview and relevant clips, with preview captions defaulting to On And an audit log and tip status update to Applied are recorded upon job completion or to Failed with error details if job fails
Evidence Links and Timestamp Accuracy
Given a tip includes evidence links to retention charts, funnel views, or heatmaps When the user clicks an evidence link Then the analytics view opens to the correct chart with the relevant region highlighted And the highlighted region aligns to the tip's timestamps within ±1 second And clicking Play Evidence starts playback at the specified timestamp within ±0.5 second And for segment-specific tips, the evidence reflects the selected channel/affiliate with displayed metrics matching the segment within ≤1% relative error
Outcome Tracking and Learning Feedback
Given a tip is Applied for an asset/segment When the change is saved Then baseline metrics (tease-to-buy conversion, preview completion rate, revenue per view) for the prior 7 days are snapshotted with the baseline window stored And after 7 full days elapse post-apply, the system computes post-change metrics and a two-proportion z-test for conversion at α=0.10 And the tip outcome is labeled Success if delta>0 and p<0.10, Regressed if delta<0 and p<0.10, otherwise Neutral, and displayed on the tip card with dates and deltas And Accepted/Applied/Dismissed statuses, actor, and reason (if dismissed) are recorded And dismissed tips reduce similar future tip frequency for the same asset by 30 days, while successful tips increase model weight for similar patterns
Goals, Alerts, and Scheduled Reporting
"As a growth lead, I want automated alerts and weekly summaries of conversion and revenue so that I can react quickly to issues and share progress with stakeholders."
Description

Allow users to set goals for tease-to-buy rate, step conversions, and revenue per asset or channel. Provide configurable alerts for anomalies and threshold breaches via email and Slack, with quiet hours and frequency controls. Offer scheduled reports (daily/weekly) summarizing funnel health, top drop-off timestamps, winning channels/affiliates, and recent recommendation outcomes. Include quick links back to affected assets and segments. Ensure role-based access controls so only authorized users receive sensitive revenue data.

Acceptance Criteria
Asset-Level Tease-to-Buy Goal Creation and Management
Given a workspace admin with Goal Manage permission When they create a goal with metric=tease_to_buy_rate, target=0.25, scope=asset:<asset_id>, aggregation_period=weekly Then the goal is persisted and appears in the Goals list for that asset and in the asset’s Paywall Insights panel And the goal is unique by (metric, scope, aggregation_period); attempting to create a duplicate is blocked with a validation error And the goal can be edited (target and period) and deleted, with all changes captured in an audit log (user, timestamp, before/after values)
Channel-Scope Step Conversion and Revenue Goal Support
Given a workspace admin with Goal Manage permission When they set a goal for metric=step_conversion_rate with step="Preview→Checkout", scope=channel:"YouTube", target=0.35 Then the goal is saved and displayed on the channel’s Goals view and contributes to alerting And values for rate metrics must be between 0 and 1; invalid inputs are rejected with inline validation Given the same admin When they set a goal for metric=revenue with scope=channel:"YouTube", currency=USD, target=500 per week Then the goal is saved with currency captured; revenue is displayed using the workspace display currency with the original currency retained for audit
Threshold Breach Alerts with Quiet Hours and Frequency Controls
Given a goal exists and alerts are enabled via email and Slack with quiet_hours=21:00–07:00 in the recipient’s timezone and frequency_window=6h When the in-period computed metric breaches the goal threshold (e.g., falls below target for tease_to_buy_rate) Then exactly one alert is generated per (metric, scope, aggregation_period) within the frequency_window And the alert payload includes metric name, scope, target, current value, deviation (% and absolute), timestamp, and quick links to the affected asset/segment and Paywall Insights detail And if the breach occurs during quiet_hours, no notifications are sent immediately; a single summary alert is delivered at 07:00 with count of occurrences during quiet hours And if Slack delivery fails, email delivery still occurs and the Slack failure is logged for observability
Anomaly Detection Alert Sensitivity and Payload
Given anomaly alerts are enabled with sensitivity=standard When the 24h rolling value for a tracked metric deviates from the 14-day baseline by z-score ≥ 3 OR by ≥ 30% relative drop/rise Then an anomaly alert is generated within 15 minutes including: metric, scope, baseline window, baseline value, current value, deviation, confidence level, and a prescriptive tip when available And changing sensitivity to low maps to z-score ≥ 4 (or ≥ 40% change) and high maps to z-score ≥ 2 (or ≥ 20% change) And disabling anomaly alerts for a scope stops further anomaly notifications within 1 minute
Scheduled Daily Reports: Configuration, Content, and Delivery
Given a user with Report Manage permission schedules a daily Funnel Health report for 08:00 America/Los_Angeles with recipients (emails and Slack channel #growth) When the next 08:00 occurs Then an email and a Slack message are delivered to all recipients And the report contains: tease_to_buy rate, step conversion rates by step, revenue by asset and channel, top 3 drop-off timestamps, top winning channels/affiliates for the last 7 days, and recent recommendation outcomes with uplift and acceptance rate And all items include quick links that deep-link to the asset/channel/affiliate/segment; opening a link loads Paywall Insights filtered to the same entity and date range And the report header states the covered time window and timezone; metrics reconcile within 1% of the Paywall Insights dashboard for the same window And if no data exists for the window, the report is still sent with a "No data for period" notice
Role-Based Access Control for Revenue Data in Alerts and Reports
Given a recipient lacks the Revenue View permission When they receive an alert or scheduled report Then revenue metrics and line items are omitted or redacted while non-revenue metrics remain visible Given a recipient has the Revenue View permission When they receive an alert or scheduled report Then full revenue data is included And if a recipient’s permission is revoked, subsequent sends reflect the change within one send cycle and the recipient is removed from revenue-only distributions And Slack deliveries honor the integration’s assigned role; if the integration lacks Revenue View, revenue fields are redacted in Slack messages
Quick Links: Deep Linking, Authentication, and Authorization
Given an alert or report includes quick links When a recipient clicks a link while authenticated and authorized for the target entity Then the target view opens with the same metric, scope, and date filters applied When a recipient clicks a link while not authenticated Then they are prompted to log in and, upon success, are redirected to the intended filtered view When a recipient lacks access to the target entity Then access is denied with a 403 message and no data is leaked And all quick links use signed URLs that expire in 24 hours
Data Export & Insights API
"As a data analyst, I want programmatic access to Paywall Insights so that I can join it with other data sources in our BI stack and run custom analyses."
Description

Provide self-serve CSV export and a secured REST API to access funnel metrics, drop-off timestamps, heatmaps, and attributed revenue. Support date range, asset, channel, and affiliate filters; pagination; and rate limiting. Deliver webhooks for purchase and funnel step events to integrate with external data warehouses and BI tools. Include API keys with role-scoped permissions, audit logs, and documentation with examples. Ensure exports respect privacy settings and exclude PII unless explicitly permitted.

Acceptance Criteria
CSV Export with Filters and Privacy Compliance
- Given an authenticated user with the Exporter role and access to assets A and B, when they request /exports/csv with start and end ISO-8601 UTC timestamps and filters asset_id=A, channel=twitter, and affiliate=AFF123, then the response is 200 within 5 seconds and the CSV contains only rows matching all filters for asset A. - Given include_pii=true is provided, when the caller's API key has scope pii:read and the workspace privacy policy permits PII export, then the CSV includes only permitted PII columns; otherwise the request is rejected with 403 and PII columns are not present. - Given include_pii is omitted or false, then the CSV excludes PII columns by default and column headers match the documented schema. - Given an invalid filter (e.g., end before start, unknown asset_id, malformed affiliate), then the response is 400 with a machine-readable error code and field-level validation messages. - Given the result set exceeds 1 million rows, then the export completes without server error and the CSV is delivered as a downloadable file with UTF-8 encoding and RFC 4180-compliant quoting, and values are timezone-normalized to UTC.
Metrics API Endpoints with Pagination
- Given a valid API key with insights:read scope, when calling GET /metrics/funnel, /metrics/dropoffs, /metrics/heatmap, and /metrics/revenue with date_range, asset_id[], channel[], and affiliate[] filters, then each endpoint returns 200 with data matching the filters and no PII present by default. - Given pagination parameters page[size] (1–1000) and page[token], when provided, then the API returns at most page[size] items, a stable cursor-based next token in links.next when more data exists, and meta.estimated_total when available. - Given an invalid or expired page[token], then the API returns 400 with an error code token_invalid. - Given requests within documented limits and typical load, then each endpoint responds within 2 seconds for page[size] ≤ 1000. - Given missing authentication, then the API returns 401; given insufficient scope or asset access, then the API returns 403; given malformed filters, then the API returns 400 with details. - All timestamps are ISO 8601 UTC; numeric fields use period decimal; response schemas match the published OpenAPI specification.
Rate Limiting and Quotas
- Given a single API key, when more than 600 requests are made within any rolling 60-second window, then subsequent requests return 429 with Retry-After and X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset headers. - Given requests remain under 600 per 60 seconds with bursts up to 60 requests in 1 second, then no 429 is returned. - Given different endpoints, then rate limits are applied per API key across all Insights API endpoints; webhook deliveries are exempt from client rate limits. - Given the rate limit window resets, then X-RateLimit-Remaining resets accordingly and requests succeed without 429. - Given a 429, then the response body includes a machine-readable error code rate_limited and suggested retry_at timestamp.
Webhooks: Purchase & Funnel Steps Delivery
- Given an event of type purchase.created or funnel.step.(entered|exited), when it occurs, then a webhook is enqueued and delivered to all enabled destinations within 10 seconds in 95% of cases. - Given a delivery attempt, then the request includes headers: X-ClipSpark-Event-Id, X-ClipSpark-Event-Timestamp (ISO 8601), and X-ClipSpark-Signature (HMAC-SHA256 over the raw body using the destination's shared secret, including a timestamp to prevent replay attacks). - Given the receiver returns a non-2xx status or times out after 10 seconds, then the event is retried up to 3 times with exponential backoff (e.g., 1m, 5m, 15m); retries stop after a 2xx. - Given duplicate deliveries, then idempotency is ensured by a stable event_id so consumers can de-duplicate. - Given workspace privacy prohibits PII or the destination lacks pii:deliver scope, then webhook payloads exclude PII; otherwise, permitted PII fields are included when explicitly enabled per destination. - Given a destination is disabled or its secret rotated, then deliveries stop immediately or use the new secret on the next attempt respectively. - Given an admin triggers "Send test event" from settings, then a test event is delivered and logged with a distinct type webhook.test.
API Key Management and Role-Scoped Permissions
- Given an Admin or Owner user, when creating an API key, then they can assign scopes (e.g., insights:read, exports:read, webhooks:manage, keys:manage, pii:read, pii:deliver) and optionally restrict to specific asset IDs; the created key is returned once with a prefix cs_ and a 40-character secret. - Given a Viewer or non-privileged user, when attempting to create, rotate, or revoke keys, then the request is rejected with 403. - Given an API call authenticated by a key lacking the required scope or asset access, then the request is rejected with 403 and no data is returned. - Given a key is rotated, then the old secret remains valid for up to 60 seconds to allow rollover and is invalid thereafter; revocation invalidates immediately. - Given a key is created or used, then the system records last_used_at and associated IP; secrets are not retrievable after creation.
Audit Logging for Access and Exports
- Given any Insights API call, CSV export initiation/download, webhook delivery attempt, or API key create/rotate/revoke, then an audit log entry is recorded with timestamp, actor (user ID or API key ID), IP, method, endpoint, request_id, status code, bytes_sent/received, scopes, and asset_ids referenced. - Given audit log queries by Admins, when filtering by date range, actor, endpoint, status code, or asset_id, then matching entries are returned within 2 seconds for up to 10,000 results with pagination beyond that. - Given audit logs are stored, then entries are immutable (append-only) and retained for at least 365 days; PII values are not stored in logs. - Given compliance export is requested by an Admin, then audit logs for a date range can be exported as CSV within 5 minutes for ranges up to 30 days.
Developer Documentation and Examples
- Given the API is published, then an OpenAPI 3.1 specification is available and up-to-date for all endpoints, parameters, schemas, error responses, and webhook payloads. - Given developers follow the docs, then at least three end-to-end examples (curl, Python, JavaScript) execute successfully against staging: (1) filtered funnel metrics with pagination, (2) CSV export with filters and PII excluded by default, (3) webhook signature verification. - Given the Postman collection is imported, then all requests execute with environment variables for API key and base URL, returning 2xx where expected. - Given docs describe rate limits and pagination, then headers and parameters in live responses match the documentation exactly. - Given contract tests run nightly, then sample requests from the docs return 2xx and response bodies validate against the published schemas.

Buyer Watermarks

Deter leaks with per-buyer on-stream watermarks (email/time) and subtle audio fingerprints. Each purchase is uniquely traceable; suspicious shares can be revoked instantly. Email-verified playback and device limits protect revenue without adding friction for legitimate buyers.

Requirements

Dynamic Buyer Watermark Overlay
"As a content owner, I want each stream to display a unique, buyer-specific watermark so that leaked video frames can be traced back and casual sharing is deterred without disrupting legitimate viewers."
Description

Render per-buyer, session-bound visual watermarks (buyer email, purchase ID/session ID, and current timestamp) directly in the video player during playback, with periodic repositioning and micro-jitter to deter cropping and automated removal. The overlay adapts to aspect ratio changes, fullscreen, PiP, and variable resolutions, avoiding key content regions and subtitles through adaptive placement rules. Opacity, rotation, and tiling patterns are tuned to remain readable yet minimally intrusive. For streamed playback, the overlay is composited client-side via Canvas/WebGL with a cryptographically seeded pattern unique to the license; for exported/downloaded clips, the watermark is server-side burned in. The system supports font fallback, RTL text, dark/light backgrounds, HDR, and high-DPI displays. Integration includes the ClipSpark web player, embed SDK, and mobile wrappers. Performance targets: <100ms added startup, <5% CPU/GPU overhead on baseline devices. All watermark seeds and mappings are recorded to associate any captured frame with a specific buyer and transaction.

Acceptance Criteria
Client-Side Overlay on Streamed Playback
Given a licensed buyer starts playback in the ClipSpark web player, When the first frame is rendered, Then the per-buyer overlay (email, purchase ID or session ID, current timestamp) is visible within 100ms added startup time and remains present for the duration of playback. Given playback is ongoing, When 7–13 seconds elapse, Then the overlay repositions to a new location chosen by a cryptographically seeded PRNG unique to the license and applies micro-jitter of 4–12px/sec drift and a rotation between −5° and +5° without exiting video bounds. Given the overlay is rendered, Then opacity remains between 12% and 22% (configurable per theme) and text has a minimum x-height equivalent of 14 CSS px at devicePixelRatio=1, scaling appropriately on high-DPI. Given the environment supports WebGL, Then compositing uses WebGL; otherwise it falls back to Canvas2D with identical visual output and behavior.
Adaptive Placement Avoids Key Content and Subtitles
Given subtitles/captions are enabled, When any subtitle line is on-screen, Then the overlay maintains ≥24px clearance from the caption bounding box and never overlaps it. Given player UI controls are visible or hovered, Then the overlay does not overlap control hit areas and maintains ≥16px clearance from them. Given the video is resized, orientation changes, or aspect ratio changes (including letterboxing/pillarboxing), Then the overlay recomputes a valid placement within 250ms and remains fully inside the visible video region with 0px overflow. Given a safe-region mask is provided via API or content analysis, Then the overlay avoids masked regions with 0px overlap throughout playback.
Performance Budget Compliance
Given overlay is enabled, When measuring startup across 100 sessions on QA baseline devices, Then the added startup latency (p95) is ≤100ms compared to overlay disabled. Given overlay is enabled, When measuring average CPU and GPU utilization during 5 minutes of 1080p30 playback on QA baseline devices, Then additional overhead is ≤5% absolute compared to overlay disabled. Given mobile low-power/battery-saver mode is active, Then the overlay reduces update frequency (no more than one reposition every ≥15s) while remaining visible, and additional overhead stays ≤5%.
Internationalization and Display Fidelity
Given buyer data contains RTL scripts and mixed LTR/RTL content, Then overlay text renders with correct bidi ordering and alignment with no character reordering artifacts. Given glyphs are missing in the primary font, Then fallback fonts render all characters without tofu/missing glyph boxes and line height variation remains within ±2px of baseline. Given HDR (PQ/HLG) or SDR content, Then overlay auto-adjusts color/opacity to maintain a contrast ratio ≥4.5:1 against the sampled background region and avoids clipping/blooming artifacts. Given devicePixelRatio ≥2, Then text and edges remain crisp without scaling blur; effective font size scales with devicePixelRatio and matches CSS sizing within ±1px.
Server-Side Burn-In for Exports
Given a user exports or downloads a clip under a valid license, Then the watermark is burned in server-side using the license’s cryptographic seed and includes buyer email, purchase ID/session ID, and per-frame UTC timestamp, with the same repositioning/jitter rules as streaming. Given the exported file is transcoded (e.g., H.264 MP4, HEVC, WebM), Then the watermark remains visible and OCR-detectable with ≥95% character recognition accuracy on a 100-frame sample. Given the exported file is played with client overlay disabled, Then the burned-in watermark remains present and visually consistent with the defined patterns.
License-Unique Seed and Traceability
Given a license is issued, Then a cryptographically strong seed (≥128 bits) unique to the license is generated and stored with buyer and transaction IDs in an immutable audit log with checksum and timestamp. Given any single captured frame from playback or an exported file, When submitted to the tracing service, Then the associated buyer and transaction are returned within 1s with 100% accuracy on a validation set of ≥100 frames across ≥10 licenses. Given audit requirements, Then seed-to-overlay mapping events (placement coordinates, timestamps, session IDs) are recorded and retained for ≥2 years with tamper-evident integrity verification.
Cross-Platform Player Modes and Embeds
Given playback in fullscreen, windowed, and Picture-in-Picture modes across the ClipSpark web player, embed SDK (cross-origin iframe), and iOS/Android wrappers, Then the overlay is present, correctly scaled, and positioned in all modes. Given the embed SDK is initialized with watermarking enabled, Then the overlay activates within the embedded player without requiring host page permissions beyond documented scopes and appears within 100ms added startup. Given device rotation or PiP enter/exit occurs, Then the overlay reflows and revalidates placement within 250ms while maintaining all clearance and visibility rules. Given network throttling or dropped frames, Then overlay repositioning uses license-seeded timers and continues at the next render opportunity without desynchronization.
Per-Purchase Audio Fingerprint
"As a rights holder, I want an inaudible fingerprint embedded per buyer so that leaked audio-only or re-encoded clips can still be traced back to the original purchaser."
Description

Embed a robust, inaudible audio watermark per purchase/session that survives common transformations (transcoding, compression, resampling, minor trimming, and typical EQ) while remaining imperceptible. The fingerprint is injected during export of full videos and highlight clips, and during live packaging for streams where feasible. A secure registry maps fingerprints to buyer, purchase, and timestamp. A verification service accepts suspect audio/video samples and returns match confidence, associated buyer, and evidence metadata. Tuning balances robustness and audio fidelity, with target false-positive rate <1e-6 and SNR impact below perceptual thresholds. Implementation includes key management for watermark seeds, batch processing for back catalog, and QA harnesses to test survivability across codec ladders (AAC/MP3/Opus, 32–320 kbps) and platform pipelines (web, iOS, Android).

Acceptance Criteria
Imperceptibility and Audio Fidelity
Given a curated set of ≥30 diverse audio segments (speech, music, mixed) and a panel of ≥20 listeners in a double-blind ABX test, When segments are watermarked at standard settings, Then the correct identification rate is not statistically greater than chance at α=0.05. And the integrated loudness difference per ITU-R BS.1770 between original and watermarked versions is ≤ 0.1 LU. And objective quality metrics show negligible degradation: POLQA MOS-LQO delta ≤ 0.10 or PEAQ ODG delta ≥ −0.10 for each segment. And no listener reports audible artifacts above a 2/5 severity median on post-test survey.
Robustness Across Codecs, Transcoding, and Edits
Given a corpus of ≥1,000 watermarked clips, When each is subjected to transformations: transcoding to AAC/MP3/Opus at 32/64/96/128/192/256/320 kbps (CBR and VBR), resampling 48↔44.1 kHz, loudness normalization to −16 LUFS, ±3 dB shelving EQ and ±6 dB narrow-band EQ, and trims of up to ±3 s at head/tail, Then the verification service returns a match for ≥99.0% of transformed samples with match_confidence ≥ 0.95 and correct buyer mapping. And across ≥100 hours of unwatermarked control audio, the observed false-positive rate is ≤ 1e−6. And time offset tolerance allows detection when up to ±3 s has been trimmed.
Fingerprint Injection Across Exports, Highlights, and Live Streams
Given an authenticated buyer exporting a full video or highlight clip, When the export completes, Then the output file contains a unique per-purchase/session fingerprint and the registry has an immutable record linking fingerprint_id → {buyer_id, purchase_id, export_timestamp}. And no two exports for different purchases share the same fingerprint_id or watermark seed. Given a live stream with watermarking enabled, When a buyer starts playback, Then the audio segments delivered to that viewer carry a session-unique fingerprint within the first two segments and for the duration of playback. And live watermarking does not increase segment start latency (time-to-first-frame) by more than 150 ms p95.
Secure Registry Mapping and Immutability
Given the watermarking service generates a fingerprint, When it writes to the registry, Then the entry is append-only, time-stamped, and cryptographically signed; subsequent updates can only add evidence metadata without altering prior fields. And registry data at rest is encrypted with KMS-managed keys and in transit over TLS 1.2+. And access control enforces least privilege: only the watermarking and verification services can create/read mappings; administrators require break-glass approval with audit logging. And given a fingerprint_id, When queried, Then the registry returns buyer_id, purchase_id, creation_timestamp, and seed_version within 200 ms p95.
Verification Service Accuracy and Performance
Given a suspect audio/video sample of 15–300 seconds, When submitted to POST /v1/verify with supported codecs (AAC/MP3/Opus) and sample rates (44.1/48 kHz), Then the response includes fields {match_confidence ∈ [0,1], fingerprint_id?, buyer_id?, purchase_id?, timestamp_ranges[], evidence{matched_frames, offsets}, processing_time_ms} and HTTP 200. And for matched samples the match_confidence ≥ 0.95 and identifiers map to the correct registry record; for unmatched samples match_confidence ≤ 0.20 and no identifiers are returned. And for a 60-second sample the end-to-end latency is ≤ 3,000 ms at p95 and ≤ 6,000 ms at p99 under a load of 10 RPS. And repeated submissions of the same payload produce deterministic outputs with match_confidence variance ≤ 0.01. And inputs exceeding size limits or unsupported formats return HTTP 415/413 with error codes and no partial matches.
Key Management and Seed Rotation
Given key material for watermark seeds is stored in a managed KMS/HSM, When seeds are requested, Then they are generated/derived per purchase/session and never reused across different purchases or sessions. And cryptographic keys are rotated at least every 90 days without invalidating verification of prior fingerprints (backward verification succeeds with new verifier). And access to keys/seeds is restricted to the watermarking service identity; access attempts are audited with user, time, and purpose; no secrets are logged. And a simulated key-compromise drill shows that revocation and re-provisioning complete within 4 hours with no increase in false positives or negatives on existing assets.
Back Catalog Batch Watermarking
Given an existing catalog of ≥10,000 assets, When a batch job is triggered to produce buyer-specific exports, Then the system watermarks outputs per purchase/session and creates corresponding registry entries with no duplication. And the batch pipeline is idempotent and resumable: rerunning after interruption does not create duplicate entries or re-process completed items. And throughput meets or exceeds 10 hours of source audio processed per wall-clock hour per node, with overall failure rate ≤ 0.5% and automatic retries (max 3) with exponential backoff. And all outputs from the batch meet the Imperceptibility and Robustness criteria defined above.
Email-Verified Playback Gate
"As a buyer, I want a quick, secure email verification step so that I can start playback easily while ensuring my viewing session is uniquely tied to me."
Description

Require successful email verification tied to the purchase before playback can start, using passwordless magic links and optional OTP fallback. Verified sessions issue short-lived tokens bound to the buyer identity used to personalize watermarks and fingerprints. Trusted devices can be remembered for a configurable period to minimize friction, with re-verification on suspicious activity (e.g., new geo/IP, high concurrency). Support includes domain-based SSO for organizations, rate limiting, bot protection, and hardening against email enumeration. The flow is integrated into the ClipSpark player and checkout confirmation, with clear UX to maintain a near-frictionless start for legitimate buyers while ensuring every session is attributable to a verified email.

Acceptance Criteria
Playback Requires Verified Email
Given a buyer with an unverified email for the purchase opens the ClipSpark player or a shared link When they press Play Then playback is blocked and a verification prompt is shown inside the player Given a buyer completes verification for the purchase When they press Play within a valid session Then playback starts without additional prompts Given an attempt is made with an email that is not tied to the purchase When verification completes Then access is denied and no playback token is issued Given a session token is expired or invalid When the player checks authorization on load Then playback is blocked and the user is prompted to re-verify
Passwordless Magic Link Verification
Given a buyer enters their email at the gate or checkout confirmation When they request a magic link Then an email is sent within 60 seconds with a single-use link valid for 15 minutes (configurable) Given the buyer clicks the magic link on the same or another device When the link is valid and not previously used Then their session is marked verified and they are returned to the player ready to play Given the magic link is expired or already used When the buyer clicks it Then verification fails with a generic message and a single-click option to resend a new link Given delivery fails or is delayed When the buyer requests resend Then resends are rate-limited per email, IP, and device to prevent abuse
OTP Fallback Verification
Given a buyer cannot access email links When they select “Use a one-time code” Then a 6-digit OTP is emailed and is valid for 10 minutes (configurable) Given the buyer enters the OTP When the code matches and is within validity Then the session is marked verified and proceeds to playback Given the buyer enters incorrect OTPs When 5 consecutive failures occur Then verification is temporarily locked for that email/device for 15 minutes (configurable) Given multiple OTP requests are made When the threshold is exceeded Then additional requests are throttled and prior unused codes are invalidated
Short-Lived Token Issuance Bound to Buyer Identity
Given a successful verification When the session is established Then a short-lived, signed token is issued containing buyer identifier (email hash), purchase ID, iat/exp, and device ID Given the player requests playback When the token is presented Then backend validates signature, expiry, audience, and binding to the device and purchase before allowing playback Given a token is revoked or expired When it is presented Then access is denied and a re-verification prompt is shown Given watermark and fingerprint rendering is initialized When the token is valid Then watermarks are personalized to the verified buyer identity from the token
Trusted Device Persistence with Suspicious Activity Re-Verification
Given a buyer verifies successfully and opts to “Remember this device” When they return within the configured trust period Then playback is allowed without re-verification using a refresh mechanism bound to the device Given the device’s IP/geo changes materially, device fingerprint changes, or concurrent sessions exceed the allowed limit When the player authorizes Then the trust is invalidated and the buyer is required to re-verify Given the trust period has expired When the buyer returns Then re-verification is required before playback Given trusted device data is cleared or corrupted When the buyer returns Then the flow gracefully falls back to standard verification without errors
Domain-Based SSO for Organizations
Given a buyer enters an email with a domain configured for SSO When they proceed Then they are offered SSO (SAML/OIDC) and redirected to the IdP to authenticate Given the IdP asserts a successful authentication for the same email When the callback is processed Then the session is marked verified for the purchase and playback is allowed Given the buyer is not authorized by the organization to access the purchase When SSO completes Then access is denied with a generic message and no token is issued Given SSO fails or is unavailable When the buyer retries Then the flow falls back to email magic link/OTP without exposing purchase existence
Rate Limiting, Bot Protection, and Anti-Enumeration Hardening
Given repeated verification attempts When requests per email, IP, and device exceed thresholds (e.g., 5/min and 20/hour) Then further requests are throttled with a generic response and a Retry-After header Given automated or bot-like behavior is detected When challenges are issued Then verification endpoints require and validate a bot challenge before proceeding Given verification is requested for an email with or without a matching purchase When responding Then the HTTP status code, response body, and UX copy are indistinguishable, and no timing-based signal (>50 ms difference) reveals purchase existence Given any throttling or failures occur When logging Then detailed reasons are captured server-side with correlation IDs without exposing specifics to the end-user
Device Limit & Concurrency Control
"As a publisher, I want to limit how many devices and simultaneous streams a buyer can use so that revenue is protected without preventing normal multi-device use."
Description

Enforce configurable device registration limits (e.g., up to 3 devices per buyer) and concurrent stream caps (e.g., 1 active playback per buyer), with clear UX for managing and evicting devices. Sessions are bound to device fingerprints and short-lived playback tokens validated at the CDN/player level. Provide grace periods and limited device swaps to reduce support friction, plus admin-configurable exceptions (e.g., classroom or enterprise seats). Handle edge cases including private browsing, PiP, and multi-tab behavior. Expose real-time session state for enforcement and telemetry, and integrate with revocation to immediately end active sessions. Performance goal: decisioning at or below 50ms per token check at the edge.

Acceptance Criteria
Device Registration Cap Enforcement at Playback Start
Given tenant policy device_limit=3 And buyer has 3 registered devices And buyer is authenticated on a fourth device with fingerprint F4 When the player requests a playback token Then token issuance is denied with HTTP 403 and error_code=DEVICE_LIMIT_EXCEEDED And response includes current_device_count=3 and a manage_devices_link And device F4 is not registered And an audit_log event device_limit_block is recorded with buyer_id and fingerprint F4 And a subsequent token request from any existing registered device succeeds with HTTP 200
Single-Concurrency Enforcement with Multi-Tab and PiP
Given concurrency_limit=1 and an active session S1 on Device A When the buyer presses Play in a second browser tab on Device A Then the player prompts to transfer playback And on confirm, S1 ends and a new session S2 starts within <=3s, leaving exactly 1 active session And on cancel, the second tab remains blocked with HTTP 403 and error_code=CONCURRENCY_LIMIT When the buyer enables Picture-in-Picture on the same tab Then no new session is created; S1 remains the only active session When the buyer presses Play on Device B while S1 is active Then the player prompts to end S1; on confirm S1 ends and Device B starts within <=3s; on decline Device B is blocked with error_code=CONCURRENCY_LIMIT
Device Management UI: List, Rename, Evict, and Swap with Grace
Given device_limit=3, swap_limit_per_30d=2, grace_period_seconds=120 And buyer has 3 registered devices including D3 actively playing When the buyer opens My Devices Then the UI lists each device with name, last_seen_at, os, browser, and registered_at When the buyer renames device D1 and saves Then the new name persists and appears in subsequent device listings and token error messages When the buyer clicks Evict on D3 and confirms Then D3's active session receives a revoke_after=120s signal and stops within <=120s And any token refresh from D3 is denied immediately with HTTP 403 and error_code=REVOKED And device D3 is removed from the list within <=5s And swap_count increases by 1; if swap_count in the last 30 days exceeds 2, further evictions are blocked with error_code=SWAP_LIMIT
Edge Token Validation and Performance SLA
Given token_ttl_seconds=300 and edge validation bound to buyer_id, device_id, and session_id claims When a valid token is presented to the CDN Then signature, expiry, and claim checks pass and a decision is returned with p95<=50ms and p99<=100ms over 10,000 requests When the token is expired, signature invalid, or device_id mismatches the session Then the CDN returns HTTP 403 with error_code in {TOKEN_EXPIRED, TOKEN_INVALID, DEVICE_MISMATCH} and no media bytes are served When a token is revoked due to policy change or admin action Then subsequent segment requests fail within <=1s and the player displays a recoverable "Session ended" state
Private Browsing and Ephemeral Device Handling
Given device_limit=3 and the buyer has 2 registered devices When the buyer initiates playback from a private/incognito window on a new physical device Then an ephemeral device record E1 is created, counts toward the device_limit, and is reusable for that window And E1 is auto-removed after 24h of inactivity or when the browser is closed, whichever occurs first When device_limit is already reached and the buyer attempts playback from a private/incognito window Then token issuance is denied with HTTP 403 and error_code=DEVICE_LIMIT_EXCEEDED, with guidance to manage devices, and no device record is created
Admin-Configurable Exceptions for Enterprise/Classroom Seats
Given a policy exception policy_id=E123 that sets device_limit=10 and concurrency_limit=5 for account A, expiring at T+30d When any buyer under account A requests playback Then enforcement uses the overridden limits while now < T+30d When the overridden limits are exceeded Then responses include HTTP 403 with the appropriate error_code and audit logs include policy_id=E123 When the exception expires Then enforcement reverts to tenant defaults within <=60s and subsequent token checks reflect the change
Real-Time Session State API and Immediate Revocation
Given an API GET /v1/session-state?buyer_id={id} When requested Then it returns active sessions (device_id, session_id, started_at, last_heartbeat_at, ip, user_agent) with p95 latency <=200ms and data freshness <=2s When an admin triggers revocation for buyer_id Then all active sessions for buyer_id stop within <=3s across regions And session-state reflects zero active sessions within <=3s And the telemetry stream emits session_end events with reason=revoked for 100% of affected sessions
Instant Revocation & Leak Traceability
"As a compliance admin, I want to trace leaked content to a specific buyer and revoke their access instantly so that further unauthorized sharing is stopped quickly and with defensible evidence."
Description

Provide an admin console and API to identify suspected leaks (via uploaded frame/audio sample or shared URL), resolve them to a buyer using visual watermark or audio fingerprint, and revoke that buyer’s access immediately. Revocation invalidates tokens, ends active sessions, blocks registered devices, and rotates watermark seeds for future sessions. Propagation target is under 2 minutes globally, with audit trails, notifications, and a reversible appeal workflow. Evidence export generates a tamper-evident report detailing the matching signals, timestamps, and mapping back to the purchase. The system maintains continuity so existing downloaded/exported media remain traceable to the revoked buyer for subsequent incidents.

Acceptance Criteria
Resolve Leak to Buyer from Uploaded Evidence
Given an admin provides either a shared URL or uploads at least one video frame and an optional 5–10s audio clip via console or API, When the system analyzes the evidence, Then it returns a single buyer match with confidence >= 0.98 using visual watermark and/or audio fingerprint, including buyerId, purchaseId, mediaId, matched timestamps, and seedVersion. Given the evidence does not match any buyer above threshold, When analysis completes, Then the response is 404 No Match with maxConfidence < 0.98 and an audit log entry is created. Given a valid request, When analysis runs, Then p95 end-to-end response time <= 15s and p99 <= 30s; all requests are audit-logged with requesterId, method (console|API), evidence hash, and outcome.
Revocation Propagates and Terminates Sessions
Given a buyer has been identified for a suspected leak, When an admin clicks Revoke Access in the console or calls POST /revocations with buyerId, Then all access/refresh tokens for that buyer become invalid within 60s, all active sessions are terminated within 90s, new session attempts receive 401 Revoked, and registered devices are blocked from new sessions. Given global infrastructure, When revocation is issued, Then propagation completes p95 <= 120s and p99 <= 180s across all regions, confirmed by synthetic probes. Then an audit trail entry is recorded with revocationId, initiator, reason, target buyer, timestamps (issued, propagated), and affected assets count.
Watermark Seed Rotation for Future Sessions
Given a revocation is issued for buyer B, When revocation is committed, Then the watermark/audio-fingerprint seedVersion for buyer B is incremented and marked active for any future reinstated access or re-purchase, and previous seedVersions remain resolvable. Given buyer B later regains access, When B starts a new session, Then the visible watermark reflects the new seedVersion and embeds B’s email and current timestamp, and the audio fingerprint corresponds to the new seedVersion.
Evidence Export Tamper-Evident Report
Given a resolved leak investigation for buyer B, When an admin selects Export Evidence, Then the system generates a tamper-evident package containing a human-readable report and a JSON manifest of matching signals (visual/audio), confidence scores, matched timestamps, evidence hashes, buyerId, purchaseId, mediaId, seedVersion(s), and action timeline. Then the package is digitally signed and includes a SHA-256 hash; verification with the platform public key succeeds; the export is stored immutably with retention >= 365 days and a download URL that expires in 24h.
Audit Trail and Notifications on Revocation
Given a revocation is executed, When the action completes, Then an immutable audit record is created with who, what, when, why, where (IP/device), evidence references, and propagation metrics, and it is visible in the admin console and via API. Then the buyer is notified via email within 5 minutes with revocation status, purchase reference, and appeal link; internal admins receive a real-time alert (webhook and console notification); no sensitive evidence content is sent to the buyer.
Reversible Appeal Workflow Restores Access
Given a buyer receives a revocation notice, When the buyer submits an appeal and an admin approves it, Then access is restored within 2 minutes globally: new tokens are issued, device blocks lifted, prior sessions remain terminated, and seedVersion remains the rotated value; audit trail records the reversal and references the original revocationId. Given an appeal is denied, When the decision is recorded, Then the buyer remains revoked, and a denial notification with reason is sent; audit reflects the outcome.
Continuity of Traceability for Existing Media
Given buyer B had downloaded or exported media prior to revocation, When a new leak incident uses those existing files and a frame/audio sample is analyzed, Then the system resolves the evidence to buyer B with correct purchaseId, mediaId, and original seedVersion, regardless of revocation status or seed rotation, with confidence >= 0.98. Then the subsequent incident can be linked to the prior revocation and included in a new export; no regeneration of files is required.
Adaptive Watermark Visibility & Accessibility
"As a viewer, I want the watermark to stay readable without covering important content so that my experience remains comfortable while still protecting the creator."
Description

Ensure watermarks are readable yet minimally intrusive and accessible. Adaptive placement avoids captions, lower-thirds, and detected faces/key visuals using ClipSpark’s scene analysis; safe regions are recalculated periodically and on resize. Visuals meet WCAG guidelines (no flashing, color-blind safe palettes, sufficient contrast via subtle outlining) while maintaining low visual dominance (e.g., 8–15% opacity). Admins can configure intensity, frequency, and allowed positions by brand/theme, but end users cannot disable the overlay. The system validates against multiple languages, scripts, and long email formats, guaranteeing legibility on small screens and high-motion content.

Acceptance Criteria
Adaptive Placement Avoids Captions, Lower-Thirds, and Faces
Given a playing video with detected captions, lower-thirds, faces, or key visuals, when the watermark position is computed, then the watermark’s bounding box plus 12 px margin does not overlap any detected region in at least 99.5% of frames over any contiguous 60-second interval. Given no non-overlapping safe region exists in a frame, when placement is computed, then the watermark auto-scales down to its minimum size and relocates to the least-overlap corner with overlap area ≤ 1% of frame area and an overflow event is logged with timestamp. Given captions toggle on or off or content updates underneath, when new regions are detected, then placement is recomputed within 250 ms and the watermark transitions to the new location with an eased animation taking 200–400 ms and without more than 1 relocation per second. Given the viewer resizes the player or changes orientation, when viewport dimensions change, then safe regions are recalculated within 200 ms and non-overlap is maintained per the 99.5% criterion.
WCAG-Compliant Visual Accessibility
Given the watermark is rendered over variable backgrounds, when computing styling, then combined fill and 1–2 px outline or shadow must produce a contrast ratio ≥ 4.5:1 against the sampled local background within a 16 px padding region for at least 95% of frames per minute. Given any opacity or fade animation, when transitions occur, then luminance changes shall not exceed 3 flashes per second and alpha change frequency ≤ 1 Hz to comply with WCAG 2.3.1. Given the smallest supported device (320 px width, 1x DPR) and SD video, when rendering text (email/time), then the x-height is ≥ 10 CSS px or ≥ 2.5% of video height, whichever is larger, and characters remain legible without clipping or overlap. Given viewers with color-vision deficiencies, when color is selected from the configured palette, then legibility remains within the 4.5:1 contrast threshold under deuteranopia, protanopia, and tritanopia simulations.
Low Visual Dominance and Opacity Bounds
Given default brand settings, when the watermark is displayed, then opacity is between 8% and 15% and the watermark occupies ≤ 3% of the frame area. Given dynamic contrast compensation in high-motion scenes, when stroke width is auto-adjusted, then stroke scales proportionally to resolution (≥ 1 px at 480p, 2 px at 1080p, 3 px at 4K) without exceeding the 3% area cap. Given continuous playback, when the watermark is persistent, then there are no pulsating or attention-grabbing animations beyond position transitions, and maximum luminance delta relative to adjacent pixels remains below 25% on average. Given any content safety rule would force overlap, when evaluating, then the system prefers smaller size over higher opacity and never exceeds 20% opacity even under overrides.
Admin Theming and Configuration Controls
Given an admin with Brand Editor role, when they open Watermark Settings for a brand/theme, then they can configure intensity (5–25% opacity), frequency (persistent or interval display with 2–60 s on/off), and allowed positions (any subset of the 5 anchors: TL, TR, BL, BR, Center). Given invalid inputs, when the admin attempts to save, then validation errors are shown inline and settings cannot be saved outside allowed ranges. Given settings are saved, when preview is generated, then the player renders the watermark with the selected theme on a test clip matching exactly the live playback behavior. Given settings are published, when any buyer plays content under that brand/theme, then end users cannot disable or hide the overlay via UI or URL parameters, and the rendered stream includes the overlay 100% of the time. Given configuration changes, when saved or published, then an audit log entry is recorded with admin ID, previous and new values, and timestamp.
Multilingual, Script, and Long Identifier Legibility
Given buyer identifiers in different scripts (Latin, Cyrillic, Greek, Arabic/Hebrew RTL, CJK), when rendered, then text shaping, BiDi ordering, and glyph fallback produce correct characters with no tofu boxes and proper joining for RTL scripts. Given a long email (up to 120 visible characters) or long buyer name, when rendered on 320 px wide screens, then the watermark uses smart soft-wrapping or shrink-to-fit to display the full identifier within two lines without overlapping safe-region exclusions and with minimum letter height ≥ 10 px. Given high-motion or low-contrast scenes, when adaptive styling is applied, then dynamic outline/shadow maintains an effective contrast ratio ≥ 4.5:1 for at least 95% of frames in each 60-second window. Given mixed-script identifiers, when rendered, then directionality marks are applied to maintain correct reading order and punctuation placement.
Real-time Safe Region Recalculation and Performance
Given ongoing playback, when no viewport or scene changes occur, then safe regions are recalculated at least every 5 seconds. Given a scene cut or major composition change is detected, when recalculation is triggered, then new placement is computed and applied within 200 ms. Given player resize or orientation change, when dimensions change, then the watermark repositions within 300 ms and remains visible throughout with no blanking longer than 100 ms. Given 1080p30 playback on the reference target device, when the watermark pipeline runs, then additional render time is ≤ 3 ms per frame on average and dropped frames attributable to the overlay remain ≤ 1% over a 10-minute session. Given frequent region fluctuations, when updates are applied, then relocation is rate-limited to ≤ 1 move per second except when avoiding imminent overlap.
Security Audit Logging & Compliance
"As a security officer, I want comprehensive, compliant audit logs so that investigations and regulatory obligations can be met without exposing unnecessary personal data."
Description

Capture immutable, tamper-evident logs for playback verifications, device registrations, token issuance/validation, watermark/fingerprint seed assignment, revocations, and admin actions. Logs include minimal necessary PII, are encrypted at rest/in transit, and retained per policy (e.g., 365 days) with configurable data residency. Provide role-based access controls, SIEM/webhook export, and DSAR tooling for data access/deletion requests. Support legal holds and evidence preservation for leak incidents, with hash-chained records to demonstrate integrity in disputes and compliance reviews (GDPR/CCPA-ready).

Acceptance Criteria
Immutable Playback Verification Logging
Given a verified buyer initiates playback of purchased content, when playback authorization is granted and the stream starts, then an audit log entry is appended within 2 seconds containing: event_type=playback_verification, event_id (UUIDv4), buyer_ref (pseudonymous), content_id, session_id, device_id, timestamp (RFC3339 ms), client_ip (/24 truncated), decision=allow, reason_code, and signature. Given playback authorization is denied, when the buyer attempts to play, then a log entry with decision=deny and reason_code is recorded with the same fields and appended within 2 seconds. Given any attempt to alter or delete an existing audit entry, when the operation is performed, then the system rejects the mutation and instead appends a compensating entry with event_type=audit_correction referencing the original event_id and actor_id, preserving immutability.
Device Registration and Token Lifecycle Audit Trails
Given a new device is used by a buyer, when the device is registered during first successful auth, then a log entry is appended with event_type=device_registration, device_id, device_fingerprint_hash, buyer_ref, prior_registered_device_count, post_registered_device_count, limit_enforced (true/false), decision=allow/deny, reason_code. Given a device limit would be exceeded, when registration is attempted, then a device_registration entry is logged with decision=deny and reason_code=device_limit_exceeded within 2 seconds. Given an access token is issued, when issuance occurs, then a token_issuance entry is logged containing token_ref (non-replayable hash), audience, scopes, expiry, buyer_ref, session_id, timestamp, and key_id used for signing. Given an access token is validated, when validation passes or fails, then a token_validation entry is logged with decision, reason_code, token_ref (hash), timestamp, and validator_service_id within 2 seconds.
Watermark/Fingerprint Assignment and Revocation Logging
Given a purchase is completed, when watermark and audio fingerprint seeds are assigned, then a log entry is appended with event_type=mark_seed_assignment, buyer_ref, content_id, watermark_seed_ref, fingerprint_seed_ref, algo_version, timestamp, and assigning_service_id. Given access is revoked for a buyer or shared link, when the revocation is executed, then a log entry is appended with event_type=revocation, buyer_ref or link_ref, actor_id, scope (content_id/all), reason_code, timestamp, and enforcement_result. Given a revoked buyer attempts playback, when the request is evaluated, then an enforcement_denied entry is logged linking to revocation_id with decision=deny within 2 seconds.
Retention, Encryption, and Data Residency Compliance
Given logs are written, when they are persisted, then they are encrypted at rest using AES-256-GCM with keys managed in KMS rotated at least every 90 days, and transmitted over TLS 1.2+ with modern ciphers. Given retention policy is 365 days, when a log entry reaches 365 days age, then it is purged within 24 hours unless a legal hold is active, and the purge action is logged with event_type=retention_purge. Given a tenant has selected a data residency region, when logs are stored and exported, then data remains within the configured region(s) and exports are served from the same region. Given data minimization is enforced, when audit entries are created, then only minimal PII is stored (buyer_ref pseudonymous ID; no full email; truncated IP), with field-level encryption for any PII fields.
RBAC and SIEM/Webhook Export Governance
Given role-based access control is configured, when a user without LogViewer privileges attempts to access audit logs, then access is denied with HTTP 403 and an access_denied audit entry is recorded. Given a user with ComplianceAnalyst role accesses logs, when they filter by buyer_ref or time window, then results are returned within 3 seconds for up to 10k records and the query is logged with event_type=log_query, actor_id, and filter_params. Given SIEM integration is enabled, when new audit entries are created, then they are exported to the configured SIEM/webhook within 60 seconds, signed with HMAC-SHA256, including a monotonically increasing sequence number and retried up to 5 times with exponential backoff on failure. Given a webhook delivery receives a 4xx with invalid signature, when retries are halted, then an export_failure alert is raised and logged with details (endpoint_id, last_status, attempt_count).
DSAR Processing and Legal Hold Preservation
Given a verified Data Subject Access Request is received, when the request is processed, then a complete export of that subject’s PII and related audit entries is produced in machine-readable format within 30 days, with fields redacted where legally required, and the DSAR action is logged. Given a valid erasure request is approved, when deletion is executed, then direct identifiers are deleted and indirect identifiers in immutable audit logs are irreversibly pseudonymized within 7 days unless a legal hold applies; the pseudonymization action is logged. Given a legal hold is placed for an incident, when applied, then targeted records are exempted from purge and erasure, and a legal_hold_applied entry is logged with hold_id, scope, actor_id, timestamp; removal of the hold is also logged.
Hash-Chained Integrity Verification for Disputes
Given audit logging is operational, when a new entry is appended, then it includes prev_hash and entry_hash computed with SHA-256 over canonicalized content, forming an unbroken hash chain per partition (tenant/region/day). Given an integrity verification is requested for a time window, when the proof is generated, then the system returns a package with chain_start_hash, chain_end_hash, count, and verification_status=pass/fail within 10 seconds for up to 100k entries. Given any entry is tampered with in storage, when the chain is verified, then verification_status=fail is returned pinpointing the first inconsistent entry_id.

Drop Scheduler

Orchestrate launches with preorders, countdown pages, and scarcity badges. Set embargo times per timezone, drip episodic releases, and auto-notify waitlists via email/SMS. Layer in early-bird pricing and bundle upsells to spike day-one sales.

Requirements

Timezone-Aware Embargo Engine
"As a creator launching a video drop, I want content locked until the specified local release time so that every audience sees it at the intended moment without leaks."
Description

Enforces content availability based on creator-defined embargo dates and times aligned to each viewer’s timezone for synchronized global releases. Integrates with ClipSpark asset delivery to gate video streams, captions, and highlight clips using signed URLs and CDN cache policies to prevent early access. Handles daylight savings, per-region overrides, and geo-IP fallback when timezone is unknown, with preview exemptions for approved reviewers. Provides audit logs for schedule changes and access attempts for compliance and troubleshooting.

Acceptance Criteria
Synchronized Global Embargo by Viewer Timezone (Local-Time Policy)
Given a release configured with policy "per-viewer local time" at 09:00, When a viewer in America/New_York requests a video stream, captions, or highlight clip at 08:59:30 local, Then each asset request returns 403 and the countdown shows remaining time within ±1 second of 00:00:30. Given the same configuration, When the viewer requests any gated asset at 09:00:00 local ±1 second, Then the request returns 200 and the asset is delivered via a valid signed URL. Given viewers in America/Los_Angeles and Asia/Tokyo, When each requests at 08:59:00 local, Then both receive 403; And when each requests at 09:00:00 local, Then both receive 200 for all asset types. Given a direct CDN asset URL without a valid signature, When requested before or after release time, Then it returns 403 consistently.
Correct Embargo Across Daylight Saving Time Transitions
Given an embargo set to 02:30 local in a timezone where the spring-forward transition skips 02:00–02:59, When the date of release occurs, Then the release happens at the next valid local instant (e.g., 03:00) and requests before that instant receive 403 while requests at/after that instant receive 200. Given an embargo set to 01:30 local in a timezone with a fall-back transition causing 01:00–01:59 to occur twice, When the date of release occurs, Then the release happens at the first occurrence of 01:30 and requests during the first 01:29 receive 403, during the first 01:30 or later receive 200, and there is no second release. Given DST rules update in IANA tzdata, When the platform updates timezone data, Then embargo evaluations use the updated rules without changing stored wall-clock schedule values.
Per-Region Release Overrides
Given a default embargo of 09:00 local and a region override setting Australia (AU) to 08:00 local, When a viewer from AU requests an asset at 07:59 local, Then the response is 403, and at 08:00 local the response is 200; When a viewer from the US requests at 08:30 local, Then the response is 403 until 09:00 local. Given overlapping override rules (e.g., AU default 08:00 and AU/NSW 07:00), When a viewer in AU/NSW requests at 06:59 local, Then the response is 403, and at 07:00 local the response is 200; When a viewer in AU/WA requests at 07:30 local, Then the response is 403 until 08:00 local. Given conflicting overrides are saved, When rules are evaluated, Then the most specific geographic rule takes precedence and is recorded in the access log entry for that request.
Geo-IP Fallback for Unknown Timezone
Given a viewer with no client-supplied timezone and blocked JavaScript, When they request an asset from an IP geolocating to America/Los_Angeles, Then embargo evaluation uses America/Los_Angeles and returns 403 before the local release instant and 200 at/after the local release instant. Given Geo-IP lookup fails or returns an unresolvable timezone, When the viewer requests an asset, Then embargo evaluation defaults to UTC and the access log records "fallback=UTC"; The response is 403 before the UTC release instant and 200 at/after the UTC release instant. Given a viewer using a VPN that geolocates to a different region than their billing country, When the request is evaluated, Then the Geo-IP timezone is used unless a per-region override tied to billing requires stricter enforcement, which is then applied and logged.
Signed URL and CDN Cache Enforcement
Given all video, caption, and highlight endpoints require signed URLs, When a non-reviewer requests any asset before embargo with or without a signature, Then the origin returns 403 and CDN cache-control prevents public caching of the 403 response. Given the embargo has passed for the viewer, When a request includes a valid signature matching the asset, user context, and unexpired timestamp, Then the response is 200; When the signature is invalid, expired, or tampered, Then the response is 403. Given the release time is changed to a later time after some signatures were minted, When the change is saved, Then previously minted signatures become invalid within 60 seconds and CDN cached positive responses are purged so that subsequent requests before the new release return 403. Given a direct CDN path without signature, When requested at any time, Then it returns 403 and is not cached publicly; After release, only signed requests return 200 and are cached per configured TTL.
Reviewer Preview Exemptions
Given a user is marked as an approved reviewer for a release, When they request any gated asset before the embargo time with a valid reviewer token, Then the response is 200 and the access log records reviewer_id and exemption=true; When the token is missing, invalid, or expired, Then the response is 403. Given a reviewer shares their signed URL, When a non-reviewer attempts to use it, Then the request is rejected with 403 because the signature is bound to reviewer identity or scope. Given reviewer status is revoked, When the reviewer attempts access using a previously valid token, Then the response is 403 within 60 seconds of revocation; Reviewer accesses are never cached publicly by the CDN.
Audit Logging of Schedule Changes and Access Attempts
Given a user creates or modifies an embargo schedule, When the change is saved, Then an immutable audit log entry is created within 60 seconds capturing actor_id, action (create/update/delete), asset_id, previous_value, new_value, timestamp (UTC), and reason (if provided). Given a viewer attempts to access a gated asset, When the request is evaluated, Then an audit event is recorded with viewer_id (if known), ip_hash, geo country/region, timezone_source (declared/geoip/utc), policy_applied, outcome (allow/deny), http_status, and evaluated_at (UTC). Given audit logs are queried via API for a date range and asset_id, When results are returned, Then entries are complete, ordered by timestamp, filterable by outcome, and exportable in NDJSON without data loss.
Preorder Checkout & Access Gate
"As a seller, I want customers to preorder and be auto-granted access at launch so that I can monetize ahead of release without manual effort."
Description

Enables secure preorders for upcoming drops with payment processing, tax handling, and automated receipt delivery, granting entitlements that unlock content at release. Connects orders to ClipSpark user accounts to enforce gating on streams, captions, downloads, and highlight reels until the embargo lifts. Supports refunds, coupons, and order webhooks for downstream systems, with fraud checks and transactional email confirmations.

Acceptance Criteria
Successful Preorder Checkout with Tax and Receipt
Given a logged-in user and a drop marked "Preorder" When the user completes checkout Then payment is authorized or captured per configuration and an order is created with status "Preorder Confirmed" And tax is calculated per buyer locale using the configured tax engine and displayed before payment And the order is linked to the buyer's ClipSpark account ID And an itemized receipt email is sent within 2 minutes including order ID, SKU/title, subtotal, discounts, tax, total, and release date/time And a preorder entitlement is created in "Locked" state for the purchased drop
Access Gate Enforcement Before Embargo
Given a user with a preorder entitlement in "Locked" state and current time is before the drop's embargo When the user attempts to access streams, captions, downloads, or highlight reels for that drop Then access is denied (HTTP 403 for API) and the UI displays a countdown to the release time in the user's local timezone And no media or captions are streamable or downloadable And the access attempt is audit-logged with user ID, resource, and timestamp
Entitlement Activation at Embargo Lift (Per Timezone)
Given a drop configured with an embargo at 10:00 in America/New_York and a user with a preorder entitlement in "Locked" state When system time reaches the embargo instant (accounting for DST) Then the entitlement transitions to "Active" within 60 seconds and the user can access streams, captions, downloads, and highlight reels And the countdown banner is removed and an "Unlocked" badge is shown And an activation event is recorded with user ID, order ID, and timestamp
Coupon Application at Preorder
Given a valid coupon code that meets usage limits and date constraints When the buyer applies the coupon at checkout Then the discount is applied to the subtotal, tax is recalculated on the discounted amount, and updated totals are shown before payment And the receipt reflects the discount line item and net total And applying an invalid, expired, or overused code shows an error and no discount is applied And single-use coupons cannot be reused by the same user across orders
Refund Revokes Access and Notifies
Given an existing preorder order When a full refund is issued Then the order status becomes "Refunded", the entitlement is revoked within 2 minutes, and the user loses access to all gated assets And a refund confirmation email is sent including refund amount, method, and processing date When a partial refund is issued Then the order status becomes "Partially Refunded" and the entitlement remains active if after release; if before release it remains "Locked" And all refund events emit a signed webhook and are audit-logged
Order and Refund Webhooks Delivery and Retry
Given webhooks are configured with a destination URL and signing secret When an order is created, updated, or refunded Then a POST is sent within 60 seconds with JSON payload including event_type, order_id, user_id, sku, amounts (subtotal, discount, tax, total), currency, status, timestamps, and an HMAC-SHA256 signature header If the destination responds 5xx or times out Then retries occur up to 6 times with exponential backoff (1m, 2m, 4m, 8m, 16m, 32m) and jitter If all retries fail Then the delivery is marked "Failed" and visible in the dashboard with last error and manual retry available
Fraud Check Holds Entitlement
Given the payment provider flags the order as high-risk or the internal fraud score exceeds the threshold When checkout completes Then the order status is "Under Review", no entitlement is activated, and the buyer receives a pending-review email When the order is approved Then the entitlement is created in "Locked" state if before release, or "Active" if after release When the order is rejected Then the payment is voided or refunded, no entitlement is granted, and a cancellation email is sent
Countdown Landing Pages
"As a marketer, I want a timezone-accurate countdown page with teasers and lead capture so that I can build anticipation and grow the audience before launch."
Description

Auto-generates branded countdown pages that reflect each visitor’s local time to the embargo and showcase teaser summaries and selected AI-generated highlights without exposing full content. Includes customizable themes, SEO-friendly metadata, social share images, and embeddable widgets to drive traffic from external sites. Captures leads via opt-in forms tied to the waitlist and supports A/B variants for optimizing conversion.

Acceptance Criteria
Localized Embargo Countdown Rendering
Given an embargo datetime is configured in UTC and a visitor’s browser timezone is detected, When the visitor loads the countdown page, Then the remaining time is displayed in the visitor’s local timezone and updates every 1 second without drift >1s over 5 minutes. Given the countdown is active, When the current time is before the embargo, Then the timer never displays negative values and does not reveal gated content. Given the current time crosses the embargo, When the page is open or refreshed, Then the state switches to "Now Live" within 1 second and the configured post-embargo CTA is displayed. Given timezone detection fails, When the countdown renders, Then the page defaults to UTC and labels the target time with the UTC timezone. Given a screen reader user visits, When the countdown updates, Then updates are announced via an ARIA live region no more than once per 5 seconds and the target local datetime with timezone abbreviation is available as accessible text.
Teaser Summaries and Highlights Without Full Content Exposure
Given teaser summaries and AI-selected highlights are configured, When the page renders, Then no individual highlight exceeds 30 seconds and the total duration of all highlights on the page is <=120 seconds. Given highlights are served, When network requests are inspected, Then media URLs are signed or tokenized, expire in <=60 minutes, and no direct URL to the full-length asset is present in markup or network calls. Given a user attempts to access full content prior to embargo, When requesting full-length media or transcripts, Then the request is denied with 403/401 and no more than 300 characters of transcript per highlight are exposed. Given search engines crawl the page pre-embargo, When sitemaps and meta are evaluated, Then full-content endpoints are excluded and only teaser metadata is advertised.
Customizable Themes and Branding
Given an editor uploads a logo (<=1 MB, PNG/SVG) and sets primary/secondary HEX colors and a font selection, When the countdown page is previewed, Then the theme applies consistently on desktop and mobile and persists after publishing. Given custom colors are applied, When contrast is evaluated, Then all text-to-background combinations on primary UI elements meet WCAG AA contrast (>=4.5:1 for normal text). Given the page is rendered, When layout stability is measured, Then CLS is <=0.1 and no flash of unstyled content occurs. Given a theme change is saved, When the page is reloaded, Then the updated branding is visible within 5 seconds via CDN invalidation or cache-busting.
SEO Metadata and Social Share Images
Given SEO settings are configured (title, description, canonical, robots), When the countdown page is fetched by a crawler, Then it returns 200 with the configured meta tags and a single canonical URL. Given social share image generation is enabled, When the URL is shared to Facebook, X/Twitter, LinkedIn, and Slack, Then the Open Graph/Twitter Card image (1200x630 or 1200x600, <=1 MB) and title/description match configuration. Given the embargo is in the future, When structured data is validated, Then JSON-LD Event schema is present with startDate equal to the embargo datetime and passes Google Rich Results test. Given the embargo has passed, When the page is re-fetched, Then meta title/description automatically switch from "Coming Soon" language to "Now Available" without creating a new URL.
Lead Capture Opt-In Tied to Waitlist
Given the opt-in form is displayed, When a user submits with email and optional phone, Then inputs are validated (email format, phone E.164), required consent checkbox is enforced, and submission completes in <500 ms p95. Given a valid submission, When the backend processes the request, Then a waitlist record is created or updated with source URL, UTM parameters, and A/B variant, and a confirmation message is shown. Given anti-abuse protections are enabled, When a bot attempts multiple submissions, Then rate limiting and CAPTCHA prevent >3 submissions per minute per IP and duplicates are de-duplicated by email. Given compliance settings are enabled, When a user opts in, Then consent text and timestamp are stored and double opt-in (if enabled) dispatches an email/SMS within 2 minutes.
A/B Variant Experimentation
Given variants A and B are configured with a 50/50 split, When 1,000 unique sessions are recorded, Then the observed split is within ±2% of target and each visitor remains in the same variant for 30 days via a cookie/localStorage key. Given conversion is defined as a successful waitlist opt-in, When events are tracked, Then variant-specific conversion rate, views, and submissions are available in analytics within 5 minutes of occurrence. Given a variant is paused, When new visitors arrive, Then no additional traffic is assigned to the paused variant within 1 minute and existing sticky assignments are respected until expiry. Given a variant configuration is invalid, When traffic arrives, Then visitors are routed to the default (control) variant and an error is logged for remediation.
Embeddable Countdown and Lead Widget
Given an embed code snippet is generated, When it is placed on an external site, Then the widget loads asynchronously in <300 ms p95, does not block host page rendering (>50 ms main-thread blocking), and is responsive from 320px to 1440px widths. Given the widget renders off-site, When timezone is detected or provided via attribute, Then the countdown matches the main page countdown within 1 second and honors the same embargo state transitions. Given cross-origin constraints, When the widget loads, Then CSP-compatible asset loading is used (single trusted domain) and no third-party cookies are set. Given the widget includes an opt-in form, When a user submits, Then the submission creates/updates the same waitlist record as the main site and attributes the source as "embed".
Drip Episodic Release Scheduler
"As an educator, I want to set a release cadence for a course so that students receive episodes on schedule without manual publishing."
Description

Schedules multi-part series to release on a configurable cadence with per-episode embargoes, automatically publishing each episode’s video, captions, and highlight clips. Updates series pages and feeds, manages visibility windows, and notifies entitled users at each release. Supports rescheduling with conflict checks, holiday skips, and API or calendar export for operational oversight.

Acceptance Criteria
Timezone-Aware Embargo and Auto-Publish
Given episode E is scheduled for 2025-10-05 10:00 America/New_York with embargo enabled When the platform reaches that instant accounting for DST Then E transitions from Embargoed to Live within 60 seconds and is accessible to authorized audiences Given any access attempt before the embargo instant When a non-admin requests E or its assets Then the system returns a placeholder or 404 and does not expose private metadata Given a missed trigger due to service downtime at the release instant When services recover Then E is automatically published within 5 minutes and the audit log records the actual publish timestamp and recovery reason
Atomic Publication of Video, Captions, and Highlights
Given E has video, captions, and highlight clips marked Ready When the publish job executes Then all three assets become visible atomically; if any asset publish fails, none are exposed and E remains Embargoed Given an asset publish failure occurs When retries are attempted Then the system retries up to 3 times with exponential backoff and logs structured errors; on final failure an alert is emitted to admins Given publish completes successfully When the episode API is queried Then it returns status=Live with non-empty, accessible URLs for video, caption file(s), and highlight clips
Series Page and Feed Update Propagation
Given E is published When the series page is loaded Then E appears in the correct order by episode number or publish time with an accurate Published At timestamp and cache is invalidated within 2 minutes Given clients poll the series feed When E is published Then the feed includes an item for E with stable GUID, correct pubDate in UTC, and media enclosures for video and captions; ETag and Last-Modified are updated Given site search is enabled When E is published Then E is indexed and searchable by title within 10 minutes
Entitled User Notifications on Release
Given an entitled user U with notifications enabled When E is published Then U receives exactly one notification per configured channel within 5 minutes containing the episode title and link, and unsubscribe preferences are honored Given a user V is not entitled or has opted out When E is published Then V receives no notification Given a notification delivery fails When retry policy is applied Then the system retries up to 2 times and records success or failure per channel in delivery logs
Rescheduling with Conflict Checks and Holiday Skips
Given an admin requests to reschedule E to time T When T conflicts with another episode in the same series or violates the set cadence Then the system blocks the change and displays a conflict message listing the conflicting episode(s) and times Given the series has a configured holiday calendar When E is scheduled on a holiday Then the system auto-shifts the release to the next non-holiday at the same local time and updates the schedule accordingly Given E is rescheduled successfully When viewing the audit trail and subscriber notifications Then the audit shows previous and new times with editor identity and reason, and subscribers to schedule updates receive a single reschedule notification
Calendar Export and API Observability
Given ICS export is enabled for the series When E is created, updated, rescheduled, or canceled Then the ICS feed reflects the change within 2 minutes using stable UIDs; reschedules increment SEQUENCE and cancellations use METHOD:CANCEL Given the public schedule API endpoint is queried with a series ID When the response is returned Then it includes embargo_at, publish_at, expire_at, status, and asset readiness flags; responses are paginated, ETagged, and rate limited Given a webhook subscriber is registered for episode.published and episode.rescheduled When those events occur Then the webhook is delivered within 2 minutes, signed with HMAC, and retried up to 3 times on 5xx responses
Visibility Windows Enforcement
Given E has publish_at and expire_at configured and preview audience set to Premium When before publish_at Then only admins and Premium users can view E in Coming Soon state; others see a countdown placeholder Given between publish_at and expire_at When a standard user accesses E Then E is visible and playable with all assets Given after expire_at When a non-admin requests E Then E is removed from listings and returns 404; admins can still access via direct URL with an Archived state
Waitlist Auto-Notifications (Email/SMS)
"As a podcaster, I want my waitlist to get instant alerts when the drop goes live so that I maximize day-one engagement."
Description

Collects and manages waitlists from countdown pages and preorders, sending automated notifications at key milestones like prelaunch reminders, go-live alerts, and last-chance prompts via email and SMS. Integrates with messaging providers through pluggable adapters, supports double opt-in and regional compliance requirements, and applies rate limiting and retry policies. Personalizes content with recipient name, timezone, and product details and reports delivery, open, and click metrics with opt-out handling.

Acceptance Criteria
Double Opt-In Waitlist Enrollment & Regional Compliance
Given a user submits the waitlist form with email and/or phone and required consent checkboxes When the user’s region is EU, CA, US, or Unknown is detected via geo-IP or user selection Then a double opt-in (DOI) message is sent via the selected channel(s) and consent evidence is recorded including consent text version, timestamp (UTC), IP, user agent, region, and source page And the contact remains in Pending status until DOI confirmation is received; Pending contacts expire after 30 days with PII purged except consent audit And SMS messages are not sent until an explicit SMS opt-in checkbox is checked and confirmed via DOI code or link And region-appropriate legal copy (GDPR/CASL/TCPA-CTIA) is displayed at collection time and stored with the enrollment record And administrators can export opt-in logs filtered by date range, region, and channel
Timezone-Aware Milestone Notifications (Prelaunch, Go-Live, Last-Chance)
Given a campaign is configured with milestone schedules (e.g., T-24h prelaunch, T0 go-live, T+48h last-chance) in a base timezone When a recipient has a stored IANA timezone (e.g., America/New_York) Then each notification is scheduled using the recipient’s local time including DST rules and sent within ±2 minutes of the scheduled time And if timezone is missing, the system infers from phone country code or email locale; if still unknown, defaults to the campaign timezone and flags the record And no recipient receives more than one notification per milestone And per-region or user-defined quiet hours are respected by deferring sends to the next permissible window
Personalized Content Rendering & Fallbacks
Given email and SMS templates contain tokens such as {{first_name}}, {{product_name}}, {{go_live_at_local}}, {{countdown_hours}}, and {{cta_url}} When a message is rendered for a recipient Then all tokens are replaced with recipient/campaign data and localized date-times And unresolved tokens are replaced with configured fallbacks (e.g., {{first_name}} -> "there") so no raw tokens appear in the sent content And SMS content is constrained to 160 GSM-7 characters per segment; if exceeding one segment, content is truncated at a word boundary with an ellipsis while preserving the CTA link And email subject and body render without empty variables and pass template validation And preview and test-send outputs match the production rendering for the same recipient data
Pluggable Messaging Adapters with Health Check & Failover
Given at least one email provider adapter (e.g., SendGrid) and one SMS provider adapter (e.g., Twilio) are configured When a provider returns a transient error (HTTP 5xx, 429, or network timeout) Then the system retries up to 3 times with exponential backoff (1m, 2m, 4m) plus jitter And upon exhausting retries, the system fails over to the next healthy provider for that channel And an idempotency key (recipient+campaign+milestone) ensures no duplicate deliveries across providers within 24 hours And provider health is checked every 60 seconds; a provider is considered healthy only after 5 consecutive successful checks And provider credentials are stored encrypted and never written to logs
Rate Limiting, Queueing, and Cross-Milestone Throttling
Given configurable provider rate limits exist (e.g., emails/min/provider, SMS/min/provider) When a batch of 10,000 recipients is triggered for a milestone Then dispatch throughput respects configured limits and messages are queued FIFO by milestone And if a provider responds with 429, the system honors Retry-After or applies exponential backoff before resuming And 95% of messages are handed off to providers within 15 minutes for batches up to 50,000 recipients under nominal conditions And no recipient receives more than one notification within any 5-minute window across all milestones (cross-milestone throttling)
Delivery, Open, and Click Metrics Reporting
Given provider webhooks are configured for delivery, bounce, open (email only), click, and unsubscribe/opt-out events When events are received from providers Then events are authenticated (signature verified), deduplicated, and persisted with recipient, campaign, milestone, and timestamps And aggregated metrics (sent, delivered, bounced, opened, clicked, unsubscribed) are exposed via API with filters by campaign, milestone, channel, and date range And metrics reflect provider counts within ±1% and are updated within 60 seconds of event receipt And SMS click tracking uses wrapped short links with unique click attribution per recipient per message And data retention policies purge personal identifiers after 18 months while preserving aggregate counts
Unsubscribe/Opt-Out and Quiet Hours Enforcement
Given emails include RFC 8058 List-Unsubscribe headers and an in-body unsubscribe link, and SMS includes STOP/HELP instructions When a recipient unsubscribes via link or replies STOP to SMS Then the recipient is added to the suppression list within 60 seconds and receives a confirmation (email or SMS) And future sends to that recipient for the same list/campaign are blocked across all providers And regional quiet hours (e.g., 9pm–8am local for US marketing messages) and user-specified preferences are enforced; messages scheduled during quiet hours are deferred to the next allowed time And opt-out/suppression events are reflected in metrics and exports
Scarcity Badges & Inventory Counters
"As a marketer, I want visitors to see accurate scarcity signals so that more people commit before the offer ends."
Description

Displays real-time scarcity indicators such as limited seats or remaining discounted units on countdown, product, and checkout views to drive urgency. Binds badge states to live inventory and pricing thresholds, updating counts atomically to avoid overselling and using read-optimized caches for traffic spikes. Provides graceful fallback messaging when inventory is exhausted and supports variant-level limits.

Acceptance Criteria
Real-Time Badges on Countdown, Product, and Checkout Views
Given a product with available inventory and an active discounted tier with remaining units And the product is visible on countdown, product, and checkout views When a user loads each view Then a scarcity badge is displayed with the correct label and numeric count appropriate to the view And the count reflects the authoritative inventory within 1 second (p95) of any change And the badge never displays negative numbers And when inventory or discounted units change due to another user's purchase, the badge updates on the user's current view within 1 second (p95); if realtime is unavailable, polling updates within 5 seconds (p95) And the badge is visible to both authenticated and guest users
Atomic Inventory Updates Prevent Oversell
Given a SKU with N remaining units (N ≥ 1) When N or more concurrent checkout attempts authorize payment for the final units Then exactly N orders succeed and 0 orders succeed beyond available units And inventory never goes below zero And inventory decrements occur atomically at payment authorization (or reservation) time And retries using the same idempotency key do not decrement inventory more than once And failed or expired authorizations restore reserved units within 60 seconds And users who lose the race receive a clear "Sold out" or "Discount exhausted" message with a non-200 error code at checkout
Variant-Level Scarcity and Display
Given a product with multiple variants each with distinct stock and discount thresholds When the product page loads and the user switches between variants Then the badge shows the correct per-variant remaining units and/or discounted units for the selected variant And a product-level aggregate badge is shown only when configured, reflecting the sum of visible variants And variants marked as unlimited suppress numeric counts and display configurable availability text And checkout enforces the selected variant's limits regardless of product-level aggregation And analytics events distinguish variant-id in badge impressions and state changes
Pricing Threshold Counters for Early-Bird Tiers
Given an early-bird pricing tier with M discounted units remaining and a base price configured When a user completes payment authorization for a discounted unit Then the discounted units remaining decrements by 1 atomically And if M reaches 0, the offer price switches to the next tier within 1 second and badges update to "Discount ended" or equivalent And users cannot be charged the discounted price once M = 0 And cancelled/failed payments restore the discounted unit within 60 seconds of failure detection And badges display "X discounted left" only while M > 0 and hide the counter when the tier is inactive
Graceful Fallback and Waitlist on Exhaustion
Given inventory or discounted units reach zero When a user views the countdown, product, or checkout pages Then badges change to a non-numeric state such as "Sold out" or "Discount ended" consistently across views And purchase CTAs are disabled or converted to a waitlist CTA where configured And checkout attempts are blocked with a clear, localized error and no payment is captured And upon restock, badges revert to numeric counts within 60 seconds and waitlisted users are queued for notification And if the inventory service is unavailable, badges display "Temporarily unavailable" without counts and purchasing is disabled until recovery
Read-Optimized Caching Under Traffic Spikes
Given sustained traffic of 2,000 requests per second to badge-related reads When badges are requested across countdown, product, and checkout views Then p95 badge render latency is ≤ 200 ms and p99 ≤ 500 ms And cache hit rate is ≥ 90% during the spike And cache TTL for counts is ≤ 2 seconds and write-through/invalidations propagate within 1 second of inventory/pricing changes And stale reads may display last-known counts but purchase flows validate against authoritative inventory to prevent oversell And error rate attributable to cache timeouts is ≤ 0.1% during the test window
Accessibility and Localization of Dynamic Badges
Given users with assistive technologies and locales such as en-US, fr-FR, and ja-JP When badges render or counts change Then badge updates are announced via ARIA live regions (polite) with meaningful text including label and count And color contrast for badge text vs background meets WCAG 2.1 AA And numeric formatting and pluralization follow the active locale And badges and associated CTAs are keyboard navigable and focus order is logical And locale changes update badge copy without page reload and without losing state
Early-Bird Pricing & Bundle Upsells
"As a seller, I want early-bird offers and bundle upsells to run automatically so that I increase day-one revenue without manual management."
Description

Configures promotional price tiers that activate and expire automatically based on time or inventory, clearly surfacing savings and remaining eligibility throughout the purchase flow. Applies rules to single products and bundles, supports cross-sell and post-purchase upsells with AI-driven recommendations from related content, and handles proration for upgrades. Logs rule changes for auditability, supports rollback, and integrates with coupons and taxes for consistent totals across channels.

Acceptance Criteria
Time-Based Early-Bird Activation by Shopper Timezone
Given an early-bird tier with start 2025-10-01 09:00 America/New_York and end 2025-10-01 17:00 America/New_York, When a shopper in Europe/Berlin visits at 08:59 ET, Then the discounted price is not applied and the standard price is shown. Given the same rule, When the shopper visits at 09:00 ET, Then the discounted price applies within 1 second and a savings label displays the absolute and percentage savings. Given a DST change in the configured timezone, When the start/end spans the transition, Then activation and expiration occur at the wall-clock times specified with no overlapping or skipped eligibility. Given multiple overlapping time-based tiers, When conditions match more than one, Then the tier with the highest priority ranking is applied and the others are ignored.
Inventory-Limited Early-Bird with Scarcity Badge
Given an early-bird tier limited to 100 redemptions, When each eligible order is completed, Then remaining eligibility decrements atomically and updates the displayed count within 2 seconds. Given remaining eligibility is <= 10% of the cap, When a shopper views the product page, Then a badge shows "Only N left" where N equals the current remaining redemptions. Given concurrent checkouts exceed remaining eligibility, When payment is attempted, Then excess checkouts are repriced to standard before capture and a message explains the change prior to confirmation. Given eligibility is exhausted or the end time is reached, When any surface (product, cart, checkout) is loaded, Then the early-bird badge and price are removed within a 60-second cache window across all channels.
Savings and Eligibility Display Across Purchase Flow
Given a shopper qualifies for an early-bird price, When viewing the product page, Then the UI shows original price, discounted price, and savings (currency and percent) with WCAG 2.1 AA contrast and accessible labels. Given the shopper proceeds to cart and checkout, When the line items are rendered, Then the same price breakdown and remaining eligibility info are shown consistently and match the order total. Given an order is placed, When viewing order confirmation and receipt, Then original vs discounted amounts are stored in line-item metadata and exposed via API for analytics. Given an API client requests pricing for the SKU, When the same conditions apply, Then the API returns identical totals (within 0.01 in the currency) and the applied rule identifier.
Bundle Pricing and AI-Driven Cross/Post-Purchase Upsells
Given a bundle rule that discounts Bundle A by 20% when at least 2 specified items are in the cart, When a shopper adds the eligible items, Then the bundle discount is applied automatically and the savings are shown in cart and checkout. Given AI-driven recommendations are enabled, When the shopper views the product page or post-purchase screen, Then at least 3 related items are recommended, excluding items already owned or in cart, with a fallback to rules-based recommendations if AI is unavailable. Given a post-purchase upsell is accepted within 5 minutes of the original order, When payment is captured, Then the upsell discount is applied according to the configured rule and a new receipt reflects the incremental charge and tax. Given cross-sell or upsell rules conflict with bundle pricing, When multiple discounts are eligible, Then the configured precedence is enforced and only the highest-priority discount is applied.
Upgrade Proration from Single to Bundle
Given a customer previously purchased Product X for $50 (pre-tax) and is upgrading to Bundle Y priced at $120, When initiating the upgrade, Then a credit of $50 is applied to the pre-tax subtotal and taxes are recalculated on the net difference. Given the customer has an active coupon on the upgrade, When the proration is calculated, Then the coupon is applied after proration per precedence rules and the effective discount is shown before confirmation. Given the upgrade is confirmed, When the order is finalized, Then the invoice shows prior payment, proration credit, new charges, and tax breakdown, and the total matches the checkout within 0.01 in the currency. Given the upgrade is canceled before capture, When the session expires, Then no charges are posted and the original entitlement remains unchanged.
Coupons and Taxes Consistency Across Channels
Given a cart qualifies for an early-bird tier and a coupon, When totals are calculated, Then the order of operations is base price -> time/inventory rule -> bundle rule -> coupon -> tax, and the result is consistent across web, embedded checkout, and public API. Given a tax jurisdiction requires tax on post-discount amounts, When calculating taxes, Then taxes are computed on the discounted subtotal and displayed as inclusive/exclusive according to regional settings. Given a coupon is excluded from discounted items, When the shopper attempts to apply it, Then the UI explains the exclusion and the coupon is not applied to those items while applying to eligible items. Given currency rounding rules, When totals are presented across channels, Then all surfaces match within 0.01 of the currency and expose the same applied rule and coupon IDs via API.
Rule Change Audit Log and One-Click Rollback
Given an admin creates, edits, or deletes a pricing rule, When the change is saved, Then an immutable audit entry is recorded with before/after values, admin ID, timestamp (UTC), IP, and optional reason within 1 second. Given an audit entry exists, When exporting logs, Then a CSV with a tamper-evident signature hash is generated and downloadable by authorized roles. Given a pricing regression is detected, When the admin triggers a rollback from a specific audit entry, Then the prior rule state is restored within 5 seconds and pricing is re-evaluated across all active sessions. Given rollback is completed, When shoppers view pricing, Then all surfaces reflect the restored rules and the audit log records the rollback action and actor.

Signal Tuner

Dial in what counts during a live stream with adjustable sensitivity, keyword weighting, and noise suppression. Create role-based profiles (e.g., sales, education, legal) to prioritize different triggers and preview markers before they fire. Outcome: fewer false positives, more high-signal moments, and alerts that match your goals.

Requirements

Real-time Sensitivity Control & Visualization
"As a live host, I want to fine-tune detection sensitivity in real time so that I can reduce false positives and catch more meaningful moments without stopping the stream."
Description

Provide an in-stream control (slider and numeric input) to adjust trigger detection sensitivity with immediate effect and no session restart. Render live visual feedback on the timeline/transcript (confidence curves, threshold line, and recent detections) so users understand the impact of changes. Persist sensitivity per role-based profile with safe defaults and guardrails (min/max thresholds, debounced updates). Changes are logged with timestamps and operator ID for auditing and later model tuning. Integrates with the detection engine to update thresholds on the fly, with rate limiting to prevent oscillation and safeguards to avoid CPU/GPU overload.

Acceptance Criteria
In-stream sensitivity adjustments apply immediately without restart
Given a live stream is active and the detection engine is connected When the operator changes the sensitivity via slider drag or numeric input Then the detection engine receives the updated threshold within 250 ms of the last change And no session restart or stream interruption occurs And the applied threshold matches the UI value within ±0.5% or 0.5 units (whichever is larger) And slider and numeric input remain in sync within 50 ms
Visualization updates reflect sensitivity changes and detections in real time
Given confidence curves are enabled and the timeline/transcript is visible When sensitivity changes Then the threshold line moves within 150 ms of the UI change And the confidence curves continue rendering at ≥30 FPS And any detection crossing the threshold in the last 10 seconds is marked as a recent detection on both timeline and transcript within 300 ms And tooltips/labels show the current threshold value and timestamp
Guardrails enforce safe defaults and valid ranges
Given a role-based profile is selected When the control loads Then the sensitivity initializes to the profile’s default within its allowed min/max range And attempts to set a value below min clamp to min and above max clamp to max And numeric input validates on blur and Enter, showing an inline error for invalid format and not applying until corrected And the control supports step increments of 0.01 via keyboard arrows And a Reset to Default action restores the profile default in ≤200 ms
Per-profile persistence across sessions and switches
Given the operator has multiple role-based profiles (e.g., Sales, Education, Legal) When the operator switches profiles during a live stream Then the sensitivity changes to the stored value for the selected profile within 250 ms and updates the engine accordingly And when the operator returns to a profile later or in a new session, the last saved value is restored And persistence is scoped to user+workspace+profile and does not leak across users or workspaces
Debounced updates and rate limiting prevent oscillation
Given the operator drags the slider continuously When rapid changes occur (>5 changes per second) Then UI previews update continuously but engine threshold updates are debounced to at most 5 updates per second And the engine confirms the last applied value after drag end within 250 ms And if updates exceed the rate limit, a subtle rate-limited indicator appears and no more than 1 pending update is queued
System safeguards maintain performance under load
Given a live stream at 1080p/30fps with detection enabled When sensitivity is adjusted and visualizations are active Then end-to-end stream frame rate does not drop by more than 5% from baseline And CPU/GPU utilization attributable to the Signal Tuner remains within budget (e.g., +10% CPU or +15% GPU), else visualizations degrade gracefully (reduced sample rate) while engine updates remain functional And no more than 0.5% of detection engine updates are dropped; dropped updates are retried once
Change events are audit-logged for tuning
Given the operator is authenticated When a sensitivity value changes (including profile switches and resets) Then an immutable audit log entry is created with timestamp (UTC), stream/session ID, operator ID, previous value, new value, source (slider/numeric/API), profile ID, and client version And logs are persisted within 2 seconds and are queryable by stream and operator within 1 minute And if logging service is temporarily unavailable, changes are queued locally and flushed within 5 minutes of reconnection without data loss
Keyword Weighting Engine with Domain Lexicons
"As a domain expert, I want to assign weights to the terms that matter to my audience so that highlights and alerts prioritize the moments that align with my goals."
Description

Enable configurable keyword/phrase weighting that influences trigger scoring across transcript and audio cues. Support exact phrases, stemming, and curated synonym groups per domain (e.g., sales, education, legal), with import/export of term lists (CSV/JSON) and per-language lexicons. Offer preset packs for each role and allow contextual boosts (e.g., boost when speaker is a guest or slides change). Provide a UI to view current weights, conflicts, and effective score impact previews. Integrate a lightweight semantic matcher (embeddings) to capture near-synonyms while capping their influence to prevent drift. All weights versioned with rollback and audit trail.

Acceptance Criteria
Scoring Engine Applies Weights and Contextual Boosts to Triggering
Given a Sales domain profile where the keyword "discount" has weight 2.0 and the base token score is 1.0, When a test clip contains three occurrences of "discount", Then the total contribution from this term equals 3 * 1.0 * 2.0 = 6.0. Given a contextual boost rule speaker_role=Guest with multiplier 1.5 active only during the second occurrence, When scores are computed, Then the contributions are [2.0, 3.0, 2.0] and the total equals 7.0. Given both boosts speaker_role=Guest (1.5x) and slides_change (1.2x) are active simultaneously, When stacking is applied with a max cap of 2.0x, Then the combined multiplier equals min(1.5*1.2, 2.0) = 1.8x. Given a trigger threshold of 5.0, When the computed score is 7.0, Then a marker is created; When the computed score is 4.9, Then no marker is created. Given live processing, When a weight is updated via the UI, Then the next scoring pass reflects the new weight within 1 second.
Exact Phrases, Stemming, and Synonym Groups per Domain
Given a Sales lexicon with EXACT:"price match" (weight 3.0), STEM:"discount" (weight 2.0), and SYN_GROUP:"rebate" group {"rebate","refund","cashback"} (weight 1.5), When processing the text "We offer price match and discounts", Then EXACT matches "price match" once, STEM matches "discounts" once, and no synonym matches are counted. Given overlapping candidates EXACT:"price match" and STEM:"match", When matching, Then EXACT takes precedence and tokens within the exact phrase are not counted separately (no double count). Given English stemming, When the text contains "discounted" or "discounting", Then STEM:"discount" matches; Given Spanish stemming, When the text contains "descuentos", Then STEM:"descuento" matches. Given the synonym group is assigned only to the Education domain, When the active domain is Sales, Then the group does not match unless explicitly included in Sales. Given word boundary enforcement, When the text contains "rebate" as part of "re-bate" without token normalization, Then no match is produced.
Import/Export Lexicons (CSV/JSON) with Per-Language Support
Given a CSV with headers [domain,language,type,term_or_phrase,weight,group_id], When imported, Then valid rows are created and invalid rows are rejected with a downloadable error report containing row numbers and reasons. Given a JSON export taken after import, When the export is re-imported, Then entries are upserted idempotently (no duplicates) and the resulting set is identical to the source. Given entries tagged with language codes en and fr, When the stream language is en, Then only en entries apply; When language fallback=enabled and fr entries lack en equivalents, Then fr entries are used according to fallback rules. Given limits max file size 5 MB and max 10,000 rows per import, When a file exceeds a limit, Then the import is blocked with a clear error stating which limit was exceeded. Given a request to export domain=Sales, language=en, format=CSV, When executed, Then the file contains only matching entries, is UTF-8 encoded, and includes the expected header row.
Role-Based Preset Packs Applied to a Profile
Given the preset pack "Sales - Discovery" containing 50 weighted terms, When applied to a new profile, Then all 50 terms are added with their types and weights, and the domain is set to Sales. Given an existing profile with overlapping terms, When the preset is applied with "override existing" disabled, Then existing weights remain unchanged and only new terms are added; When enabled, Then overlapping terms are updated to preset values. Given a preview action, When the user clicks "Preview changes", Then a diff shows counts of additions, updates, and removals (if any) before applying. Given the user applies the preset, When the operation completes, Then a success notification appears and a version history entry records "Preset applied" with a summary of changes.
Semantic Matcher with Influence Cap and Drift Controls
Given a semantic matcher with cosine similarity threshold 0.82 and an influence cap of 0.3x the curated keyword's weight, When text contains a near-synonym of "discount" with similarity >= 0.82, Then its contribution equals curated_weight * 0.3; When similarity < 0.82, Then contribution equals 0. Given a curated synonym group match and a semantic match candidate for the same span, When scoring, Then the curated synonym contribution is used and the semantic contribution is suppressed (no double count). Given the active domain is Legal, When a semantic match relates to a Sales-only keyword, Then it does not contribute to scoring. Given an admin toggle "Enable semantic matching", When disabled, Then no semantic contributions are applied or logged. Given a global cap of 40% for semantic contributions per sample, When multiple semantic matches occur, Then the sum of semantic contributions does not exceed 0.4 * the sum of curated contributions.
Versioning, Rollback, and Audit Trail for Weight Changes
Given any create, update, or delete of lexicon entries or weights, When saved, Then a new immutable version is recorded with version_id, UTC timestamp, actor, change set, and optional reason. Given a version history with multiple entries, When a user rolls back to version k, Then the active configuration equals version k and a new version entry records the rollback event and actor. Given an audit export request for a date range, When executed, Then a CSV/JSON is produced listing before/after values, actor, timestamp, and correlation IDs per change. Given role permissions, When a user without "Manage Weights" attempts a change, Then the action is denied and no version is created. Given active live streams, When a rollback is applied, Then new scoring passes use the rolled-back configuration within 1 second and the UI displays the active version ID.
UI Displays Weights, Conflicts, and Effective Score Impact Preview
Given the Lexicon & Weights UI with domain=Sales and language=en selected, When loaded, Then the table displays columns [type, term/phrase, weight, domain, language, conflicts] with sort and filter controls. Given duplicate or overlapping entries that create conflicts, When detected, Then a conflict badge is shown and clicking it reveals conflict details and available resolution actions. Given a transcript snippet is entered, When "Preview effective score" is clicked, Then matches are highlighted and per-match contributions and totals are displayed for current vs proposed changes. Given a user adjusts a weight from 1.0 to 2.0 in the preview, When the change is made, Then the previewed scores update in under 200 ms without persisting the change. Given contextual boosts are configured, When preview runs, Then boosts and caps are visualized per match with tooltips showing final multipliers.
Low-Latency Noise Suppression & VAD Pipeline
"As a live producer, I want background noise minimized without noticeable delay so that detection accuracy improves and the stream remains responsive."
Description

Introduce a preprocessing stage combining noise suppression, automatic gain control, and voice activity detection to stabilize input quality with <100 ms added latency. Provide adjustable suppression levels and profile presets, with automatic fallback if system resources are constrained. Distinguish speech, music, and environmental noise to reduce spurious triggers from non-speech audio. Expose health metrics (latency, CPU/GPU usage) and allow per-session toggling. Feed cleaned audio and VAD segments into the ASR and trigger detectors to improve accuracy. Ensure graceful degradation and failover to raw input with clear UI indication.

Acceptance Criteria
Live Stream Latency Budget Adherence (<100 ms)
Given a live audio stream at 48 kHz mono with 20 ms frames and the default profile active When the preprocessing pipeline (noise suppression + AGC + VAD) is enabled Then the additional end-to-end latency introduced by preprocessing is <= 100 ms at the 95th percentile and <= 120 ms maximum over a continuous 30-minute session And the latency health metric displayed in the UI updates at least once per second and reflects the measured value within ±5 ms
Adjustable Noise Suppression Levels and AGC Stability
Given the session settings panel is open When the user sets noise suppression to Off, Low, Medium, or High Then the change takes effect within 1 second and introduces no audible gap > 50 ms And at Medium, signal-to-noise ratio on the reference noisy sample set improves by ≥ 6 dB while STOI remains ≥ 0.92 And AGC maintains short-term speech loudness at -18 LUFS ± 2 LU over 10-second windows and limits clipping to < 0.1% of samples
VAD Accuracy and Non-Speech Discrimination
Given the reference evaluation set containing speech, music, and environmental noise When the pipeline runs with default VAD sensitivity Then VAD achieves speech/non-speech F1 ≥ 0.92 and music false positive rate ≤ 5% And VAD segment boundary mean absolute error is ≤ 20 ms versus reference annotations And segments labeled non-speech are not forwarded to ASR or trigger detectors
Resource-Aware Degradation and Failover with UI Indication
Given a live session where CPU > 85% or GPU > 90% is sustained for ≥ 5 seconds or free memory drops below the configured threshold When the resource monitor detects constraint Then the pipeline degrades in this order: switch to lightweight suppression model → reduce suppression level by one step → disable suppression → disable AGC → fail over to raw input while preserving audio continuity And each transition is logged and surfaced in the UI within 1 second with a clear "Degraded" or "Raw Input" badge And no audio gap > 50 ms occurs during any transition And when resources recover below thresholds for ≥ 10 seconds, the prior configuration is automatically restored and the UI badge clears
Health Metrics Exposure (Latency, CPU/GPU) and API Access
Given an active session When the user opens the Health panel or queries the metrics API Then the UI displays added latency (ms), CPU%, GPU%, active model tier, and VAD state, updating at ≥ 1 Hz And a WebSocket endpoint streams the same metrics as JSON with timestamps at ≥ 1 Hz And metrics are recorded in session logs at 1-minute granularity for at least 24 hours And crossing warning thresholds (latency > 100 ms, CPU > 85%, GPU > 90%) changes indicator color and emits a warning event
Per-Session Preprocessing Toggle and ASR/Trigger Data Flow
Given an active session When the user toggles Preprocessing Off Then ASR and trigger detectors consume raw audio within 500 ms and a "Preprocessing Off" indicator appears in the UI with no audio gap > 50 ms When the user toggles Preprocessing On Then ASR receives cleaned audio and VAD segment timing via the documented interface with segment boundary alignment error ≤ 20 ms, applied within 500 ms, and the UI indicator updates accordingly And on the standardized noisy ASR test set, enabling preprocessing yields ≥ 10% relative WER improvement versus raw input
Role-Based Profile Presets Apply and Persist
Given role presets Sales, Education, and Legal are available When a user selects a preset Then the preset applies default values for suppression level, VAD sensitivity, AGC target, and music discrimination weighting within 1 second without audio gap > 50 ms And the selection persists for the user's next session unless explicitly changed And on the corresponding domain evaluation sets, the chosen preset reduces non-speech-trigger false positives by ≥ 30% compared to Default while maintaining speech-trigger recall within 5% relative
Role-based Profiles & Shared Presets
"As a team lead, I want standardized, shareable profiles so that my team’s streams consistently highlight what matters for our domain."
Description

Allow creation and management of role-based profiles (Sales, Education, Legal, Custom) that bundle sensitivity thresholds, keyword weights, trigger types, and noise settings. Include curated presets with recommended thresholds per role and the ability to clone and customize. Support org-level shared profiles with RBAC (owner, editor, viewer) and versioning with change notes and rollback. Profiles can be selected at session start or switched mid-stream with atomic application of settings and instant preview. Provide migration and defaulting logic so existing users start with sensible presets.

Acceptance Criteria
Create Role-Based Profile with Bundled Settings
- Given I am an org member with permission to create profiles, When I create a new profile selecting role = Sales, Education, Legal, or Custom and provide valid sensitivity thresholds, keyword weights, trigger types, and noise suppression settings, Then the profile is saved, assigned a unique name within the org, and appears in my profile list within 1 second. - Given invalid or missing fields, When I attempt to save, Then the save is blocked and field-level error messages specify the violated rule (range, required, type) without creating a profile. - Given a created profile, When I retrieve it via UI or API, Then the stored values exactly match those entered (weights preserved to two decimal places) and are returned consistently. - Given a created profile, When I edit and save changes, Then the update succeeds and the profile reflects the new values immediately in UI and API responses.
Curated Presets and Clone/Customize
- Given I am a user, When I open the presets gallery, Then curated presets for Sales, Education, and Legal are available, read-only, each with recommended thresholds and settings. - Given a curated preset, When I select Clone, Then a new editable profile is created in my org with all settings copied and a default name "Copy of <Preset>" and the original preset remains unchanged. - Given a cloned profile, When I modify any setting and save, Then the changes persist and subsequent sessions using this profile apply the new settings. - Given a name collision on clone or rename, When I save, Then the system enforces org-unique names by prompting me to choose a unique name.
Org-Level Shared Profiles with RBAC
- Given a profile owned by a user, When the owner shares it with the org and assigns roles (owner, editor(s), viewer(s)), Then role assignments are saved and visible on the profile. - Given a viewer, When they attempt to edit or delete the shared profile, Then the action is blocked with a permission error and no changes are made. - Given an editor, When they update settings or change notes, Then the save succeeds and a new version is created; editors cannot transfer ownership or change the owner role. - Given any user, When they apply a shared profile to a session, Then viewers and editors can apply; only the owner can unshare or delete the profile.
Versioning with Change Notes and Rollback
- Given a profile, When I save changes with optional change notes, Then a new version is created with incremented version number, timestamp, author, and notes. - Given version history, When I view it, Then I can see past versions with their metadata and the currently active version indicated. - Given a selected past version, When I perform rollback, Then the profile’s active settings exactly match that version and a new top version is created noting the rollback source. - Given concurrent edits, When another user saves a change before I do, Then my save is rejected with a version conflict message until I refresh to the latest version.
Profile Selection and Mid-Stream Atomic Switch with Instant Preview
- Given the session start dialog, When I select a profile and start streaming, Then all tuner settings are applied before the first frame is processed and the active profile name is displayed. - Given an ongoing live stream, When I choose a different profile and click Apply, Then the new settings take effect atomically within 500 ms, with no mixed-configuration period, and triggers after the switch use only the new settings. - Given preview mode, When I hover/select a profile before applying, Then preview markers update to reflect the selected profile within 200 ms without firing real triggers or altering the live configuration. - Given a switch in progress, When a failure occurs, Then the system reverts to the prior profile without data loss and displays an error message.
Migration and Defaulting for Existing Users
- Given an existing user with no profiles at first login after release, When they open Signal Tuner, Then they are prompted to select a role; if they defer, a sensible default Custom profile is auto-created and applied. - Given prior per-user tuning settings (pre-feature), When migration runs, Then an equivalent Custom profile is created with parameter deltas not exceeding 5% from prior values and marked with change notes "Auto-migrated". - Given migrated or defaulted profiles, When the user begins a session, Then the default profile is preselected and can be changed without errors.
Parameter Validation and Limits Enforcement
- Given the profile editor or API, When sensitivity thresholds, keyword weights, trigger types, or noise suppression values are set outside supported ranges, Then the system rejects the change with specific field-level messages and does not modify the profile. - Given boundary values for each parameter, When saved, Then values are accepted and preserved without unintended rounding (weights preserved to two decimal places). - Given a profile import or bulk update, When multiple fields are invalid, Then all violations are reported in one response with field-level details.
Pre-Fire Marker Preview & Manual Override
"As a moderator, I want to review and confirm markers before they publish so that only high-signal events are surfaced."
Description

Before a trigger becomes a committed marker/alert, show a preview chip on the live timeline with confidence score, trigger reason (e.g., weighted terms, sentiment spike), and a transcript/audio snippet. Allow operators to accept, edit, snooze, or dismiss markers; sub-threshold events require manual confirmation based on a configurable auto-fire threshold. Provide keyboard shortcuts and a batch review drawer to act on multiple previews quickly. Committing a marker writes an immutable event with provenance metadata; dismissed items feed back into tuning analytics to reduce future false positives. Target added decision latency under 500 ms when manual gating is enabled.

Acceptance Criteria
Live Preview Chip Appears with Context Within 500 ms
- Given a live stream with manual gating enabled, When a trigger is detected, Then a preview chip renders on the live timeline within 500 ms (p95) and no marker is committed. - And the preview chip displays: confidence score (0–100%), active role profile name, trigger reasons (e.g., top 3 weighted terms and/or sentiment spike), a transcript snippet of 6–10 seconds aligned to the trigger, and a 5-second audio snippet with play/pause controls. - And the preview chip is anchored to the correct timestamp within ±250 ms of the trigger timecode.
Single-Preview Manual Actions and Keyboard Shortcuts
- Given a focused preview chip, When the operator presses A or clicks Accept, Then a marker is committed and removed from previews, with UI acknowledgment within 200 ms. - Given a preview chip, When the operator presses E or clicks Edit and updates title, tags, category, or adjusts start/end time (within ±10 seconds of the trigger), Then saving commits a marker with edited values and removes the preview. - Given a preview chip, When the operator presses S or clicks Snooze and selects 15s, 30s, or 60s, Then the preview hides immediately and reappears after the selected duration if not already handled. - Given a preview chip, When the operator presses D or clicks Dismiss, Then no marker is committed, the preview is removed, and a tuning analytics record is created. - Given keyboard focus on a preview, When shortcuts A/E/S/D are pressed, Then the corresponding actions execute on that preview without affecting others.
Auto-Fire Threshold and Manual Gating Logic
- Given an auto-fire threshold T (0.00–1.00) configured for the active role profile, When manual gating is disabled and event confidence ≥ T, Then the system auto-commits a marker within 200 ms (p95) and no preview is shown. - Given the same threshold T, When manual gating is enabled, Then no event auto-commits; all events surface as previews and require operator confirmation, with added decision latency staying under 500 ms (p95). - Given an event confidence < T, When a preview is shown, Then it never auto-commits and requires manual Accept to commit. - Given T is changed during a session, When a new trigger occurs, Then the updated T applies within 2 seconds and does not retroactively alter existing previews.
Batch Review Drawer for Bulk Actions
- Given at least one preview exists, When the operator opens the batch review drawer and selects N previews (1–100), Then bulk Accept, Dismiss, and Snooze actions are enabled. - When bulk Accept is executed for up to 50 previews, Then all selected markers are committed within 2 seconds (p95); for 51–100 previews, completion occurs within 5 seconds (p95), with per-item success feedback. - When bulk Dismiss is executed, Then no markers are committed and per-item tuning analytics records are created. - When bulk Snooze is executed with a chosen duration, Then all selected previews hide immediately and reappear after the duration unless already handled. - Given an item in the selection was already acted upon, When a bulk action runs, Then that item is skipped and reported as "already handled" without failing the batch.
Immutable Marker Commit with Provenance Metadata
- Given a marker is committed (Accept/Edit or batch), Then the system persists an immutable event containing: eventId, committedAt (UTC), committedBy (userId or "system"), roleProfileId, confidenceScore, triggerReasons with weights, timecodeStart/timecodeEnd, transcriptSegmentId(s), gatingMode (manual|auto), decisionPath (accept|edit|batch), and a content hash. - When any client attempts to modify a committed marker, Then the API rejects the change with 409 Conflict and logs an audit entry. - When a marker is committed after Edit, Then the record includes editDelta fields describing changed attributes relative to the preview proposal.
Dismissal Feedback to Tuning Analytics
- Given a preview is dismissed, When the action completes, Then a tuning analytics event is recorded with fields: triggerType, reasons, confidence, roleProfileId, userId, dismissReason (required), and optional note. - Then the dismissed item is excluded from active markers and appears in analytics dashboards within 60 seconds of dismissal. - When multiple previews are dismissed in a batch, Then one analytics event per preview is recorded with a common batchId linkage.
Accessibility, Error Handling, and Concurrency Safeguards
- Given keyboard-only operation, When navigating timeline previews and the batch drawer, Then all actions (Accept, Edit, Snooze, Dismiss, open/operate batch) are operable via keyboard and have visible focus indicators. - Given a screen reader is active, When a preview chip receives focus, Then it announces confidence, trigger reasons, and available actions via accessible labels. - Given a network error during commit, When the operator retries, Then the system ensures at-most-once commit; duplicates are not created and the user receives clear retry/success feedback. - Given two operators act on the same preview, When one action commits or dismisses it, Then the other operator is notified within 1 second that it was already handled and no duplicate events are created. - Given the audio snippet cannot be generated, When the preview renders, Then it shows transcript-only state with an "Audio unavailable" indicator without blocking other actions.
Alert Routing & Notification Controls
"As a content operations manager, I want alerts delivered to the right channels at the right cadence so that my team can act quickly without being overwhelmed."
Description

Configure routing rules for committed markers to in-app banners, Slack/Teams, email, webhooks, and OBS overlay, with per-trigger type channels, rate limits, cooldowns, batching, and quiet hours. Provide a test mode to simulate alerts without impacting production channels. Include delivery status and retry/backoff for webhooks with signed requests. Allow per-profile routing templates and per-session overrides. Integrate with existing ClipSpark notification services and ensure idempotency to avoid duplicates.

Acceptance Criteria
Per-Trigger Routing with Profile Templates and Session Overrides
Given a committed marker with trigger type "Keyword Hit" and active profile "Sales" And the "Sales" routing template maps "Keyword Hit" to Slack, Teams, and in-app banner And a per-session override adds Email for "Keyword Hit" When the marker commits Then an in-app banner is shown in the current session within 2 seconds And a Slack message is sent to the configured channel containing session name, trigger type, marker title, and timestamp And a Teams message is sent to the configured channel containing session name, trigger type, marker title, and timestamp And an Email is sent to the session owner with subject including the session name and trigger type And each delivery record transitions from "Queued" to "Sent" or "Failed" within 10 seconds And routing uses the existing ClipSpark Notification Service v2 queue and records provider tracking IDs And if the routing job is retried, no duplicate deliveries are created for the same marker/channel due to idempotency keys
Rate Limits and Per-Trigger Cooldowns
Given a rate limit of 20 alerts per minute for Slack and a 30-second cooldown for trigger type "Sentiment Spike" And 50 "Sentiment Spike" markers commit within 1 minute in the same session When routing executes Then no more than 20 Slack messages are sent in that minute And for the session, no two "Sentiment Spike" Slack messages are sent within 30 seconds of each other And suppressed alerts are logged with reason "RateLimited" or "Cooldown" and include marker IDs And session analytics shows counts of sent and suppressed per channel and trigger type
Quiet Hours with Critical Trigger Overrides
Given quiet hours are configured from 22:00 to 07:00 local time for Email and Slack And trigger type "Legal Risk" is flagged as Critical and exempt from quiet hours When a "Keyword Hit" marker commits at 23:15 Then no Email or Slack notification is sent and the alert is deferred And the in-app banner displays immediately And the deferred alert is delivered at 07:00 with original marker timestamp preserved When a "Legal Risk" marker commits at 23:30 Then Email and Slack notifications are sent immediately And delivery logs include a QuietHoursApplied flag true/false for each delivery
Channel and Trigger-Based Batching for Email
Given batching is enabled for Email with a 5-minute window and max 10 items per batch for trigger type "Topic Detected" And 17 "Topic Detected" markers commit within 5 minutes When routing executes Then two batch Emails are sent: first containing 10 markers and second containing 7 markers And the second Email subject includes "[Batch 2/2]" And each Email body lists each marker's title and timestamp And delivery logs record batch ID, batch size, included marker IDs, and send timestamps
Test Mode Simulation Without Production Impact
Given test mode is enabled for the session And routing rules map "Keyword Hit" to Slack, Email, Webhook, and OBS Overlay When a test alert is triggered Then no messages are sent to production Slack or Email endpoints And a sandbox Webhook endpoint receives the request with headers including "X-ClipSpark-Test: true" And the Webhook request signature verifies using the test secret And the OBS overlay displays a TEST badge with the marker preview for 5 seconds And the in-app banner displays "Simulated alert" with the list of channels And delivery logs record status "Simulated" and do not increment rate limit, cooldown, or batching counters
Webhook Delivery: Signing, Retries, Backoff, and Idempotency
Given a Webhook subscription configured with HMAC-SHA256 signing and a shared secret And an idempotency window of 10 minutes is configured And the endpoint returns HTTP 500 for initial deliveries When a committed marker triggers the Webhook Then the request includes headers "X-ClipSpark-Signature" and "X-ClipSpark-Event-ID" And signature verification succeeds using the shared secret And retries occur with exponential backoff of approximately 2s, 4s, 8s, 16s, and 32s (max 5 attempts) And delivery status transitions Queued -> Retrying (with attempt counts) -> Failed after max attempts, with timestamps When a replay is attempted with the same Event ID within 10 minutes and the endpoint returns HTTP 200 Then the event is suppressed as a duplicate and logs reason "DuplicateSuppressed" And a successful delivery stores response code, latency, and signature verification result
OBS Overlay and In-App Banner Rendering Resilience
Given OBS overlay routing is enabled for trigger types "Highlight" and "Milestone" with per-session styling overrides (font, color, duration) And a "Highlight" marker commits When routing executes Then the OBS overlay displays a lower-third with marker title and timestamp within 1 second using the session's styling overrides And the in-app banner shows a clickable control to jump to the marker timecode And a rendering failure for the overlay is logged with severity "Warn" and does not block Slack/Email/Webhook deliveries And delivery status for overlay is recorded separately from other channels

Crowd Pulse

Fuse audience energy into detection by ingesting chat, reactions, and poll spikes from YouTube, Twitch, Zoom, Teams, and more. Correlate sentiment surges with on-screen moments to surface share-worthy clips driven by real engagement. Benefit: clips that resonate because they mirror what the audience cared about most.

Requirements

Multi-Platform Engagement Ingestion
"As a content creator, I want ClipSpark to automatically ingest audience interactions from my streaming platforms so that engagement data can power highlight detection without manual exports."
Description

Build robust connectors to ingest live and VOD audience signals—chat messages, emoji/reactions, likes, Q&A, and poll events—from YouTube, Twitch, Zoom, and Microsoft Teams. Support OAuth 2.0, webhooks and/or polling with pagination, rate limiting, retries, deduplication, and backfill for post-event recordings. Normalize payloads into a common schema capturing source, event_type, content, counts, hashed author_id, message_id, channel/meeting identifiers, and both source and server timestamps. Provide operational metrics, error handling with dead-letter queues, and graceful degradation when a source is temporarily unavailable.

Acceptance Criteria
OAuth 2.0 Authorization for All Platforms
Given platform connectors are configured with client credentials and required scopes for YouTube, Twitch, Zoom, and Teams When a user initiates platform connection Then the OAuth consent flow completes and a refreshable access token is stored with its expiry and scopes per platform Given a valid refresh token is within 5 minutes of access token expiry When the system checks token health Then the access token is refreshed proactively and the new expiry is persisted without user interaction Given an access token is revoked or expires When an API call returns 401 or 403 Then the connector is marked degraded, requests are retried with exponential backoff, and the user is prompted to re-authenticate within 60 seconds via status event Given authentication events are logged When tokens are issued or refreshed Then no raw tokens, secrets, or PII are logged; only hashed connector identifiers and non-sensitive metadata are recorded
Live Ingestion via Webhooks and Polling with Rate Limits
Given a platform supports webhooks When a new engagement event (chat, reaction, like, Q&A, poll) occurs Then the system receives the webhook within 5 seconds, responds 2xx, and processes the event idempotently Given a platform lacks webhooks or webhook delivery is failing When polling is enabled Then the connector polls at the configured interval, respects platform rate limits, uses cursors/ETags/since tokens, and paginates until no more data remains Given HTTP 429 or rate-limit headers are returned When requests exceed platform thresholds Then the connector applies Retry-After or exponential backoff with jitter and maintains error rate < 1% with zero account bans during a 1-hour soak test Given overlapping polling windows or duplicate webhook deliveries occur When events are ingested Then duplicates are not stored (idempotency key = source + message_id or platform-unique event key) and exactly-once persistence is achieved
Post-Event VOD Backfill
Given a completed recording with available engagement history When a user connects the recording for backfill Then the system ingests 100% of chat, reactions, likes, Q&A, and poll events from start to end across all pages Given an ingestion interruption occurs during backfill When the service restarts Then progress is resumed from the last checkpoint (persisted at least every 1000 events or 10 seconds), completing without duplication Given API pagination limits apply When fetching historical pages Then the connector follows nextPageToken/continuation/cursor until exhausted and reports a total ingested count equal to the source-reported total (±0.5% where only approximate totals are available)
Common Engagement Schema Normalization
Given an event is received from any supported platform When it is normalized Then the record contains: source, event_type ∈ {chat_message, reaction, like, qna, poll_opened, poll_vote, poll_closed}, content (text or standardized emoji code), counts (integer ≥ 0), hashed author_id (SHA-256 with per-tenant salt), message_id (source-unique), channel_or_meeting_id, source_timestamp (RFC3339), and server_timestamp (RFC3339) Given optional fields are missing in the source payload When normalization occurs Then required fields are validated, optional fields are null-safe, and invalid records are rejected to the DLQ with a reason code Given potential clock skew in source timestamps When events are persisted Then server_timestamp is set at receipt and time_skew_ms is computed; 99% of events have |time_skew_ms| < 300000, with outliers flagged for monitoring Given emojis/reactions and poll events are ingested When normalized Then reactions map to standardized codes with counts, and poll events include poll_id, option_id, option_text, and vote_count when provided by the source
Idempotent Storage and Deduplication
Given duplicate deliveries with the same message_id or equivalent unique key (source + normalized content hash + source_timestamp within 1s) When events are persisted Then only one record exists in storage and deduplicated attempts increment a dedupe_drops_total metric Given at-least-once webhook retries and overlapping polling windows When ingestion runs under load Then idempotent put semantics ensure no more than one record per unique event and reconciliation jobs report 0 duplicates per 100k events Given DLQ events are replayed When reprocessing occurs Then previously persisted unique events are skipped without duplication and 99th percentile end-to-end replay latency for 10k events is < 2 minutes
Operational Metrics, Observability, and Alerts
Given ingestion services are running When metrics are scraped Then the system exposes per-source and per-event_type counters (events_ingested_total), errors_total, dedup_drops_total, lag_seconds, webhook_latency_ms, polling_requests_total, rate_limit_backoffs_total, dlq_depth, and connectors_health gauges Given SLO thresholds are defined When a breach occurs Then alerts trigger within 2 minutes for: no events for 5 minutes on a live source, error_rate > 2% over 5 minutes, dlq_depth > 1000, or lag_seconds_p95 > 60 Given logs and traces are emitted When requests are processed Then correlation IDs and platform response codes are included, sampling is configurable, and no PII (raw author IDs or message text) is logged
Graceful Degradation and DLQ Processing
Given a single source is unavailable or returns persistent 5xx/timeouts When health checks fail Then only that connector is marked degraded with exponential backoff while other connectors continue unaffected, and per-source status is exposed via API/UI Given a malformed or unprocessable event is encountered When validation fails Then the event is routed to a dead-letter queue with reason, encrypted raw payload, and retryable flag; DLQ supports filtered replay by source and time window Given the unavailable source recovers When health checks pass Then backlog is drained respecting rate limits at > 200 events/sec until lag_seconds < 10, without exceeding error_rate > 1%
Timecode Synchronization & Event Normalization
"As a producer, I want engagement events aligned precisely to my video timeline so that detected moments reflect what was on screen when the audience reacted."
Description

Synchronize external engagement events to the video timeline, compensating for stream latency, recording start offsets, and clock skew across platforms. Produce canonical absolute and relative timestamps aligned to the media file and transcript timeline. Maintain per-source offset estimation via periodic heartbeats and drift correction, with confidence scoring. Handle gaps and out-of-order delivery, and index normalized events for low-latency queries by time range to support downstream detection and UI overlays.

Acceptance Criteria
Cross-Platform Event Alignment to Media Timeline
Given a recorded media file with known UTC start time and ingested events from multiple platforms with platform timestamps and variable latencies When normalization runs on the batch/stream Then each output event includes normalized.t_utc (ISO 8601 Z) and normalized.t_media_s (seconds from media start, 3-decimal precision) and normalized.source present and non-null And the median absolute alignment error versus ground-truth anchor markers is ≤ 200 ms and the 95th percentile is ≤ 400 ms over a 60-minute session And normalized.t_media_s ∈ [0, media_duration] and is monotonically non-decreasing per source
Per-Source Offset Estimation via Heartbeats & Latency Changes
Given per-source heartbeat messages at ≥ 10 s intervals carrying source timestamp and receive time And a step change in network latency up to ±1.5 s occurs When the offset estimator processes the next heartbeats Then the estimated source offset converges within 2 heartbeats to within ±150 ms of the true offset And each update emits normalized.source_offset_s and normalized.confidence ∈ [0,1] And when heartbeat density ≥ 6/min and p95 jitter ≤ 200 ms, confidence ≥ 0.8; otherwise confidence scales down linearly to a minimum of 0.3 And any detected offset jump > 2 s is flagged and corrections are slewed such that no single adjustment produces a time jump > 300 ms
Drift & Clock Skew Correction over Long Sessions
Given a continuous session of 120 minutes with per-source clock skew up to ±50 ppm When drift correction is applied Then the cumulative drift between normalized.t_media_s and ground-truth anchors at end-of-session is ≤ 300 ms And corrections are applied via slewing (rate adjustment), not step jumps, with no instantaneous adjustment > 100 ms And no retrograde timestamps are emitted; event order per source remains stable after correction
Canonical Timestamp Output & Monotonicity
Given any normalized event emitted by the pipeline When inspecting the payload Then it contains normalized.t_utc (ISO 8601 Z with millisecond precision), normalized.t_media_s (number with 3-decimal precision), normalized.source_offset_s (float seconds), and normalized.confidence ∈ [0,1] And normalized.t_utc equals media_start_utc + normalized.t_media_s within ±10 ms computational tolerance And for any two input events from the same source with original timestamps t1 ≤ t2, their normalized.t_media_s satisfy n1 ≤ n2 And ties (n1 == n2) are deterministically ordered by source_event_id ascending
Robustness to Gaps, Duplicates, and Out-of-Order Events
Given event streams that may contain duplicates, gaps, and out-of-order delivery up to 3 s late When normalization processes the stream Then a reordering buffer of at least 5 s produces output in chronological order with added end-to-end latency ≤ 500 ms And duplicate events (same source_event_id) are dropped idempotently so only one normalized event is emitted And gaps ≥ 10 s do not cause pipeline errors; processing continues and confidence decays per heartbeat availability And late events beyond the reordering window are tagged late=true and inserted without breaking monotonicity
Low-Latency Time-Range Querying for Normalized Events
Given an index containing 100k normalized events for a 1-hour media file When querying any 5-second time range Then p95 query latency ≤ 100 ms for a warm index and ≤ 300 ms on cold start And results are strictly sorted by normalized.t_media_s ascending with stable ordering for equal times And newly ingested normalized events become queryable within ≤ 1 s end-to-end
UI Overlay Sync with Playback and Transcript
Given video playback at 1.0x and 1.5x speeds with user scrubbing to arbitrary positions When the UI renders engagement overlays using normalized.t_media_s and transcript tokens aligned to the same timeline Then overlays align to the corresponding transcript tokens and video frames within ±200 ms for 95% of interactions and never exceed 350 ms error And overlays appear within 500 ms after starting playback And pausing/resuming over 10 minutes does not accumulate overlay drift > 100 ms
Sentiment & Surge Detection Engine
"As a streamer, I want automatic detection of meaningful sentiment surges so that the most resonant moments are identified for clipping."
Description

Compute multilingual sentiment and excitement scores for chat/reactions using NLP with emoji weighting, language detection, and toxicity/spam filtering. Aggregate signals into per-second engagement series and detect statistically significant surges using configurable rolling windows (e.g., z-score/Poisson/Bayesian approaches). Emit surge entities with start/end, peak time, magnitude, drivers (top messages, poll outcomes, reaction bursts), source mix, and confidence. Support real-time streaming and batch reprocessing modes with feature persistence for repeatable analyses.

Acceptance Criteria
Real-time Multilingual Sentiment with Emoji Weighting
Given a live chat stream containing messages in multiple languages with emojis When each message is processed within a 1-second ingestion window Then the engine assigns per-message sentiment in [-1,1] and excitement in [0,1] with p95 model inference latency ≤ 200 ms And language is detected with ≥95% accuracy on a labeled validation set and routed to the matching per-language model And emoji contributions are weighted per config, such that defined emojis (e.g., 🔥, 😂, 👏) shift excitement by their configured deltas regardless of surrounding text And messages with undetected language receive neutral sentiment (0 ± 0.05) and capped excitement ≤ 0.1
Toxicity and Spam Filtering Exclusion from Signals
Given an incoming stream containing toxic messages and spam patterns (duplicates, repetitive bursts, bot-like cadence) When toxicity_score ≥ configured threshold or spam rules match Then such messages are excluded from all aggregates and surge detection And filtering achieves ≥0.90 recall and ≥0.95 precision on the labeled moderation test set And each filtered event is logged with a reason_code and trace_id, retrievable for 7 days with 99% availability
Per-Second Engagement Series Aggregation Across Sources
Given chat, reactions, and poll events from YouTube, Twitch, Zoom, and Teams When aggregating to a per-second series Then the system outputs for each second: timestamp_utc, sentiment_avg, excitement_avg, volume, reactions_rate, polls_delta, source_mix_percentages And source weights are configurable; default equal weighting; updates take effect within 60 seconds without downtime And time alignment error relative to source timestamps is ≤100 ms and missing seconds are backfilled with zeros
Configurable Surge Detection with Multiple Algorithms
Given a configurable rolling window (e.g., 30s) and selected algorithm (z-score, Poisson, Bayesian online change point) When applied to the engagement series Then surges are emitted when metrics exceed configured thresholds with an evaluated false positive rate ≤5% on the benchmark corpus And sensitivity parameters (e.g., window size, min_lift, min_duration) are runtime-configurable and versioned with audit logs And in streaming mode, p95 detection latency is ≤2s from the true peak timestamp
Emitting Surge Entities with Required Fields and Drivers
Given a detected surge When the surge entity is created Then it includes: surge_id (UUID), start_ts, peak_ts, end_ts, peak_magnitude, contributing_metrics, drivers.top_messages[3], drivers.reactions[type,count], drivers.poll_outcomes, source_mix, confidence ∈ [0,1] And top_messages are deduplicated, language-tagged, and ranked by attribution score And the entity validates against the published schema (JSON/Avro) with 100% schema validation pass rate and backward compatibility maintained
Real-Time and Batch Modes with Persistence and Repeatability
Given streaming mode under 500 msgs/sec and 2000 reactions/sec sustained load When processing end-to-end Then p95 latency from ingestion to surge emission is ≤3s with zero data loss And in batch reprocessing of a 2-hour recording with identical configuration, surge boundaries and magnitudes achieve ≥0.95 Jaccard similarity to prior results And intermediate features are durably persisted with content-addressed identifiers enabling byte-for-byte reproducibility under identical inputs
Fault Tolerance, Idempotency, and Backpressure
Given transient sink failures or duplicate deliveries When processing continues Then the pipeline retries with exponential backoff and achieves at-least-once ingestion with exactly-once aggregation via idempotent writes And backpressure signals throttle ingestion while maintaining SLA for p90 traffic And after a 5-minute outage, the system catches up within 10 minutes without emitting duplicate surges
Engagement-Driven Clip Candidate Generator
"As an editor, I want clip candidates generated from engagement peaks so that I can publish highlights quickly with minimal manual trimming."
Description

Translate detected surges into ranked clip candidates by mapping peaks to configurable pre-roll/post-roll windows and merging overlaps. Score candidates using magnitude, recency, diversity, sentiment polarity, and speaker importance from transcripts. Attach auto-generated titles, key quotes, and captions via existing ClipSpark pipelines. Expose one-click export to the highlight workflow and provide APIs/UX controls for users to adjust clip boundaries and selection rules.

Acceptance Criteria
Ranked clip candidates from multi-platform engagement surges
Given a processed video session with detected engagement peaks from at least one supported platform When the Engagement-Driven Clip Candidate Generator runs with default settings (topK=50) Then it produces a ranked list of 0–50 clip candidates ordered by descending score, with deterministic tie-breakers (recency, then earliest start) And each candidate includes: candidateId, startMs, endMs, score[0..1], sourcePeakIds[], platformBreakdown, createdAt, and videoId And all start/end times are within [0, mediaDuration] and start < end And the generation completes within 30s of receiving the last peak for live sessions or within 60s of job start for VOD And the same inputs produce identical outputs on repeated runs (score variance ≤ 0.001)
Configurable pre/post windows and overlap merging
Given default preRoll=5s and postRoll=10s When peaks are mapped to candidate windows Then each window is [peakTime - preRoll, peakTime + postRoll] clamped to [0, mediaDuration] And when windows overlap or have gaps < 1s, they are merged into a single candidate with start=min(starts), end=max(ends), and sourcePeakIds=union And candidates shorter than 3s after clamping are discarded; candidates longer than 120s are truncated to 120s And, when a transcript is available, start/end snap to the nearest sentence boundary within ±1s; otherwise they remain unchanged And running the merge procedure twice yields the same set of windows (idempotent)
Multi-factor scoring with configurable weights and fallbacks
Given default weights wMagnitude=0.35, wRecency=0.20, wDiversity=0.15, wSentiment=0.15, wSpeaker=0.15 (sum=1.0) When scores are computed Then each candidate receives a score in [0,1] and increasing any individual factor (others fixed) does not decrease the final score (monotonicity) And administrators can update weights via UI/API; each weight ∈ [0,1] and sum must equal 1.0 or the update is rejected with 400 And if any factor is unavailable for a candidate, its weight is redistributed proportionally to available factors and the condition is logged And diversity reduces scores for candidates with cosine similarity > 0.85 to any higher-ranked candidate in the same session And ties are broken by higher magnitude, then more recent peakTime, then earlier startMs And repeated runs on identical inputs yield scores within ±0.001
Auto-generated titles, key quotes, and captions attached to candidates
Given a generated candidate When enrichment runs via existing ClipSpark pipelines Then the candidate has a title ≤ 80 characters in the dominant audio language, without trailing punctuation artifacts And it has 1–3 key quotes, each verbatim from the transcript, 8–120 characters, with quoteStartMs/quoteEndMs within the candidate window And it has a captionsUri for WebVTT with cue coverage ≥ 95% of the candidate duration and average cue offset < 300ms And if any enrichment artifact fails, the candidate is marked incomplete and excluded from one-click export; the system retries up to 3 times with exponential backoff And enrichment status and errors are visible in logs and candidate metadata
One-click export to Highlights workflow and API
Given a complete candidate visible in the UI When the user clicks "Export to Highlights" or calls POST /v1/highlights {candidateId} Then the API responds within 2s (p95) with 201 and highlightId And the highlight appears in the Highlights queue with matching startMs, endMs, title, captions within 10s (p95) And repeating the export within 10 minutes returns 200 with the same highlightId (idempotent) and no duplicate highlight is created And exporting an incomplete candidate returns 409 with a descriptive error; unauthorized requests return 401 And an analytics event highlight_exported is emitted with candidateId, highlightId, projectId
User-adjustable clip boundaries and selection rules via UI and API
Given a list of generated candidates When a user adjusts start/end via drag handles or numeric inputs Then values snap to the nearest word boundary and satisfy: start ≥ 0, end ≤ mediaDuration, duration ∈ [5s, 120s] And the preview updates within 500ms (p95) and re-validates against selection rules And users can configure project-level rules (minScore, uniqueSpeakers, sentiment range, maxClipsPerHour) via UI and PUT /v1/clip-rules with validation And rule changes re-rank and filter the candidate list deterministically within 5s (p95) And all adjustments are audit-logged with userId, before/after, timestamp
Audience Heatmap & Explainability Overlay
"As a video editor, I want an engagement heatmap with context so that I can understand and trust why specific moments are recommended."
Description

Render an engagement heatmap on the editor timeline with peak markers and interactive explanations of "why"—top chat snippets, reaction counts, and poll results at that moment. Provide filters by source, sentiment, and language; tooltips with confidence scores; accessible color contrast and keyboard navigation; and performant virtualization for long videos. Allow export of heatmap visuals and underlying JSON for downstream sharing and analytics.

Acceptance Criteria
Heatmap Rendering with Peak Markers on Timeline
Given a processed video with engagement events and a loaded editor timeline When the timeline view is opened Then a heatmap spanning the full video duration is rendered with bin size computed as 1s (<30min), 5s (30–120min), or 10s (>120min) Then the top 5 peaks by normalized engagement score are marked with peak markers labeled with their timestamps (hh:mm:ss) Then the playhead alignment to the heatmap remains within ±1s of the underlying event timestamps during playback and scrubbing Then hovering a peak marker displays the peak’s exact normalized score (0–100) within 150ms Then bins with no data are visually indicated as gaps without breaking the heatmap continuity
Interactive Explainability Overlay for Peaks
Given a peak marker is clicked When the explainability overlay opens Then it displays the top 5 chat snippets (deduplicated, truncated to 140 chars with ellipsis) from ±10s around the peak, each with platform, timestamp, language code, and sentiment tag Then it displays reaction counts per source and poll results (question and winning option with percentage) for the same window Then every snippet links to the original message/deeplink when available Then the overlay loads within 300ms after click for cached data, and within 1s when fetching Then closing the overlay via Esc, click outside, or Close button hides it and restores focus to the originating marker
Filtering by Source, Sentiment, and Language
Given filters for Source (YouTube, Twitch, Zoom, Teams, Other), Sentiment (positive, neutral, negative), and Language (ISO 639-1 multi-select) are available When the user applies any combination of filters Then the heatmap, peak markers, and explainability overlay update to reflect only matching events within 200ms for videos ≤2h and 400ms for >2h Then an empty-state message “No engagement matches the selected filters” appears if no events match Then the current filter state persists for the session and is included in exports as metadata
Tooltips and Confidence Scores
Given the cursor hovers over any heatmap bin or the keyboard focuses a bin When a tooltip is requested Then a tooltip appears within 150ms showing the bin’s time range, normalized engagement score (0–100), event counts per source, sentiment distribution (%), and model confidence (0.00–1.00) Then if model confidence < 0.50, a “Low confidence” indicator with an aria-label is present Then the tooltip remains visible while hovered/focused and does not obscure the playhead position by more than 20px
Accessibility: Color Contrast and Keyboard Navigation
Given WCAG 2.2 AA requirements When rendering the heatmap, markers, overlays, and tooltips Then text and interactive elements meet contrast ratio ≥4.5:1; non-text UI indicators meet ≥3:1 Then all interactive components are reachable and operable via keyboard (Tab/Shift+Tab/Arrow keys/Enter/Escape) including: focusing the heatmap, moving by one bin with Left/Right, opening the overlay with Enter, closing with Escape, and toggling filters with Space/Enter Then screen reader users receive meaningful labels and roles for heatmap, peak markers, bins, overlays, and filter controls Then automated accessibility tests (axe-core) report zero critical violations on the heatmap views
Performance and Virtualization for Long Videos
Given a video of 6 hours with 500k+ engagement events When the editor timeline loads Then initial heatmap render completes in ≤1.5s on a standard workstation (4-core CPU, 8GB RAM, Chrome latest) Then timeline scrolling and zooming maintain ≥60 FPS with no main-thread blocks >100ms Then DOM nodes for bins/markers in the viewport do not exceed 2,000 and offscreen bins are virtualized (not present in DOM) Then memory usage attributable to the heatmap component remains ≤200MB during interaction
Export Heatmap Visual and Underlying JSON
Given the user clicks Export When choosing “Heatmap (PNG)” or “Heatmap (SVG)” or “Engagement JSON” Then the downloaded file includes metadata: videoId, createdAt (ISO 8601), binSizeSec, filters, timeZone, schemaVersion Then exported visuals exactly reflect current filters and viewport; JSON reconstructs heatmap scores with deviation ≤0.5% Then the export completes with HTTP 200 or local file save within 2s for videos ≤2h and 5s for >2h Then the export filename follows pattern: {videoId}_heatmap_{YYYYMMDD_HHmmss}_{format}
Privacy, Consent & Compliance Controls
"As an account admin, I want clear privacy and consent controls so that our use of audience data complies with policies and protects participant identities."
Description

Implement privacy-by-design controls: pseudonymize user identifiers, redact PII from chat on ingest with configurable entity detection, and enforce per-source retention windows. Provide admin settings to enable/disable sources, require consent prompts for meetings (e.g., Zoom), and honor deletion requests. Encrypt data in transit and at rest, maintain audit logs, and enforce platform Terms of Service and regional data residency configurations.

Acceptance Criteria
PII Redaction on Chat Ingest (Configurable Entities)
Given entity detection is configured per source and enabled for Email, Phone, Address, and a custom regex "employee_id=\d+" And chat messages in English and Spanish containing those entities are ingested from YouTube, Twitch, Zoom, and Teams When ingestion completes Then 100% of occurrences of the configured entities are redacted in stored records, search indexes, analytics pipelines, and UI views using standardized placeholders [EMAIL], [PHONE], [ADDRESS], [CUSTOM] And the redaction metadata (type, count, source, timestamp) is written to the audit log And entities not enabled in configuration remain unmodified And processing latency added by redaction is ≤ 50 ms per message at p95 under 200 msgs/sec load
Pseudonymization of Audience Identifiers
Given ingestion receives user identifiers (usernames, display names, platform IDs) and optional avatars from supported platforms When data is stored or displayed Then raw identifiers are replaced by stable per-tenant, per-project pseudonyms derived via non-reversible hashing with a tenant-specific salt And the same origin user within the same project maps to the same pseudonym; across tenants and projects the mapping is not linkable And raw identifiers do not persist in databases, logs, exports, caches, or analytics outputs And automated tests verify 0 occurrences of raw identifiers via regex scans across storage snapshots and logs for sampled datasets
Per-Source Retention Windows Enforcement
Given an admin sets per-source retention windows: YouTube=180 days, Twitch=90 days, Zoom=30 days, Teams=60 days And data older than each configured window exists in primary storage, derived clips, transcripts, captions, and indexes When the scheduled retention job runs Then all records older than the window are hard-deleted from primary storage, derived artifacts, caches, and search indexes for that source And corresponding object storage assets are deleted and any pre-signed URLs become invalid immediately And an audit log entry is created for each deletion batch with counts, source, time range, and outcome And reprocessing from backups is blocked for deleted items; backups are pruned to remove expired data within 7 days And queries and analytics exclude deleted data immediately after the job completes
Admin Source Controls and Meeting Consent
Given an admin disables ingestion for Twitch When new Twitch events arrive via webhook or poll Then no data is ingested, a compliance error is logged, and the UI shows a warning banner within 1 minute; the status API reflects "Disabled" for Twitch Given Zoom integration has "Require participant consent" enabled When a Zoom meeting starts without consent recorded by Zoom Then no meeting content is ingested and a compliance log entry is created with reason "Consent missing" When consent is recorded by Zoom during a meeting Then ingestion begins only after consent time; any pre-consent content is not ingested
Right-to-Be-Forgotten Deletion Requests
Given a verified data subject or tenant admin submits a deletion request for a specific user pseudonym or for a specific video/source When the request is accepted Then all associated data is deleted from primary storage, derived artifacts, caches, and search indexes within 24 hours And processing queues are purged of related items And an immutable audit log entry is recorded capturing requester (role), scope, timestamps, and outcome without storing PII content And the status endpoint exposes request state transitions: Received -> In Progress -> Completed/Failed And subsequent re-ingestion of the same event IDs is blocked unless explicitly re-authorized by an admin
Encryption In Transit and At Rest
Given data is transmitted between connectors, APIs, services, and storage When connections are established Then TLS 1.2+ with modern cipher suites is enforced; weak protocols/ciphers are disabled; HSTS is enabled for public endpoints Given data is stored in databases, object storage, queues, and logs Then AES-256 (or cloud provider equivalent) encryption at rest is enabled with keys managed in KMS And keys are region-scoped to match data residency configuration and rotated at least annually or upon compromise And automated compliance checks run daily and alert on misconfiguration or drift
Audit Logging, ToS Enforcement, and Data Residency
Given any action occurs: ingest, access/read, export, policy change, deletion, consent decision When the action completes Then an audit log entry is recorded with actor/service, tenant, source, object IDs, UTC timestamp, outcome, and reason And audit logs are write-once (WORM), retained for at least 400 days, and are tamper-evident via hash chaining/verifiable digests Given a source's Terms of Service prohibits a detected ingestion scenario (e.g., private streams without permission) When such a scenario is flagged by platform metadata or admin configuration Then ingestion is blocked and an explanatory error is surfaced in UI/API and audit log Given tenant data residency is set to a region (e.g., EU) When data is processed and stored Then all storage, compute, and backups remain in the configured region; cross-region transfers are blocked and attempts are logged

BackCapture DVR

Continuously buffer the last 30 seconds to 5 minutes so every spike includes its build-up, not just the punchline. When a moment hits, auto-stitch pre-roll + post-roll into a clean, branded clip without manual scrubbing. Result: never-miss context and instant, ready-to-share highlights.

Requirements

Rolling Buffer Engine (30s–5m)
"As a live-session host, I want the last few minutes always buffered so that I can instantly pull context around unexpected moments without rewinding or re-recording."
Description

Continuously captures and maintains a rolling buffer of the last 30 seconds to 5 minutes of the active audio/video stream, configurable per workspace and session. Ensures A/V sync, low-latency access, and adaptive resource usage across CPU/GPU with spillover to disk when needed. Supports live recordings, virtual meetings, and in-app playback sessions. Provides resilience to network jitter and dropped frames with graceful degradation of quality under load. Integrates with ClipSpark’s media ingestion pipeline and encryption services to keep buffered data ephemeral and secure until a capture is requested.

Acceptance Criteria
Configurable Buffer Window per Workspace and Session
- Given a workspace with default buffer window set to 60s, When an admin updates the workspace buffer window to any value between 30s and 300s (inclusive), Then the new default persists and applies to new sessions within 5 seconds. - Given an active session, When a session override buffer window is set to a value between 30s and 300s, Then the session uses the override immediately without interrupting capture and the override does not affect other sessions. - Given invalid input (below 30s, above 300s, or non-numeric), When saving buffer window settings, Then validation prevents save and surfaces a specific error message and the previous valid value remains active. - Given a session with an override, When the session ends, Then the override is discarded and the workspace default remains unchanged.
Instant Clip Capture with Pre-Roll + Post-Roll Stitching
- Given a configured pre-roll P (≤ current buffer window) and post-roll Q, When a user triggers capture at time t0, Then the resulting clip includes media from [t0−P, t0+Q] with frame-accurate boundaries and audio-video drift ≤ 20 ms. - Given a capture request, When the post-roll window Q completes, Then the stitched clip is handed to the media ingestion pipeline within 2 seconds and marked ready. - Given P exceeds available buffered duration, When a capture is triggered, Then the clip includes the maximum available pre-roll and the clip metadata flags partial-pre-roll=true. - Given the stream ends before Q elapses, When a capture is triggered, Then the clip truncates to available post-roll and metadata flags partial-post-roll=true. - Given brand settings are enabled, When a clip is emitted, Then watermark/bumper is applied according to workspace branding without re-encoding the buffered pre-roll more than once.
Low-Latency Buffer Access and A/V Sync
- Given a healthy system load (CPU<70%, disk IO wait<10ms), When a capture is requested, Then the first byte of buffered media is readable within 200 ms and the full pre-roll is available without blocking. - Given random seeks within the current buffer, When seeking to any timestamp within the last N seconds, Then seek latency is ≤ 150 ms (p95). - Given continuous playback from the buffer, When measured over any 5-minute interval, Then cumulative A/V sync drift stays ≤ 20 ms (p95) and never exceeds 40 ms. - Given 30/60 fps sources, When clips are rendered, Then duplicated or dropped frames do not exceed 0.1% of total frames.
Adaptive Resource Management with Disk Spillover
- Given a per-session memory cap M is configured, When buffer usage would exceed M, Then the engine spills oldest segments to encrypted disk without interrupting capture. - Given spillover is active, When reading spilled segments during capture, Then added read latency from disk is ≤ 300 ms (p95) and continuity is maintained (no gaps >100 ms). - Given a workspace disk quota, When required disk exceeds quota, Then the engine gracefully reduces buffer bitrate/resolution to stay within quota while preserving continuous coverage. - Given spill files age out or are captured, When their TTL expires or downstream acknowledges receipt, Then spill files are securely deleted within 10 seconds.
Resilience Under Network Jitter and Dropped Frames
- Given simulated jitter with 50–200 ms spikes and 5% packet loss for 30 seconds, When capturing the stream, Then audio continuity is maintained with gap concealment and video degrades to lower FPS/resolution without hard freeze > 500 ms. - Given transient network loss up to 2 seconds, When the connection resumes, Then the buffer self-recovers without process restart and A/V sync re-stabilizes to ≤ 40 ms within 3 seconds. - Given sustained bandwidth reduction of 50%, When load persists for 60 seconds, Then the encoder adapts within 5 seconds to maintain uninterrupted buffering with at most one resolution step down (e.g., 1080p→720p). - Given any degradation, When it occurs, Then the system emits a structured "degradation_mode" event with timestamps and cause, and emits a "recovered" event within 1 second of stabilization.
Security: Ephemeral Encryption and Data Lifecycle
- Given buffered media segments are written to memory or disk, When stored, Then they are encrypted with AES-256-GCM using keys from the workspace KMS and IVs are never reused. - Given data in transit, When segments are streamed between components, Then TLS 1.2+ with modern ciphers is enforced and plaintext media is not logged. - Given segments age out without capture, When the buffer window slides past them, Then segments are purged and securely overwritten (or cryptographically shredded) within 60 seconds. - Given a capture completes and downstream acknowledges ingestion, When acknowledgment is received, Then all corresponding buffered artifacts are deleted within 5 seconds. - Given access attempts, When an unauthenticated or unauthorized reader requests buffered data, Then access is denied and the attempt is audited with no media leakage. - Given a process crash or restart, When the service restarts, Then any residual spill files are detected and shredded within 30 seconds and keys are not persisted on disk.
Source Type Coverage: Live, Virtual Meetings, and In-App Playback
- Given a live recording source, When a 10-minute session runs with buffer window N, Then captures during minutes 3, 6, and 9 produce clips with correct pre-roll/post-roll bounds and A/V sync criteria met. - Given a virtual meeting source, When the active speaker switches rapidly (≥5 switches/min), Then the buffer maintains continuity and captures reflect the correct video stream without desync. - Given an in-app playback session (HLS/DASH/MP4), When the user scrubs and pauses, Then the buffer tracks playback and captures include the correct segments relative to playback time. - Given unsupported source constraints, When a source lacks required APIs, Then the system surfaces a clear "BackCapture unavailable for this source" status and disables capture without crashes.
One-Tap Capture Triggers (UI + Hotkey + API)
"As a presenter, I want to hit a single button or hotkey to save the moment so that I don’t break flow or fumble through menus during a live session."
Description

Provides immediate capture controls to commit the buffered pre-roll plus a configurable post-roll window. Offers a prominent UI button, global hotkeys, and a simple REST/SDK endpoint for external trigger events (e.g., control surfaces, stream decks). Debounces duplicate triggers, supports per-user permissions, and attaches session metadata (speaker, topic, tags) at capture time. All triggers write to a unified capture queue with timestamps for auditability.

Acceptance Criteria
UI One-Tap Capture Commits Pre/Post-Roll
Given an active recording session with a rolling buffer length >= configured pre-roll When the user clicks the Capture button Then a capture is queued that includes exactly [configured pre-roll] seconds before click time and [configured post-roll] seconds after click time Given the buffer length < configured pre-roll When the user clicks Capture Then the capture uses the entire available buffer as pre-roll and appends the full configured post-roll When a capture is queued Then the app shows a confirmation within 500 ms and assigns a unique capture_id And the queue item records: capture_id, user_id, session_id, source='UI', enqueue_time (UTC ISO 8601), start_time, end_time, pre_roll_seconds, post_roll_seconds, status='queued' And the resulting clip applies the user’s active brand template
Global Hotkey Background Trigger and Debounce
Given a configured global hotkey and ClipSpark running When the user presses the hotkey while another app is focused Then a capture is queued with the same pre/post-roll rules as the UI trigger and source='Hotkey' When the user presses the hotkey multiple times within a 1500 ms debounce window Then only one capture is created and the duplicates are recorded as suppressed events in the audit trail When the hotkey is pressed Then the user receives a non-blocking confirmation (toast or sound) within 500 ms Given the configured hotkey conflicts with an OS-reserved shortcut When the user attempts to save it Then the app prevents the save and prompts the user to choose a different combination
REST API Trigger with Auth, Idempotency, and Rate Limits
Given a valid OAuth2 bearer token with capture:write scope When a POST /v1/captures/trigger request is sent with optional metadata and an Idempotency-Key header Then the API responds 202 Accepted with capture_id and source='API' and enqueues a capture with configured pre/post-roll Given the same Idempotency-Key is retried within 10 minutes Then the API returns the original 202 response body without creating a duplicate capture Given the client exceeds 10 trigger requests per user per 10 seconds When additional requests arrive Then the API responds 429 Too Many Requests with a Retry-After header Given an invalid or insufficient token Then the API responds 401/403 accordingly and no capture is enqueued When the API trigger is processed Then an audit record is written with request_id, user_id, ip_hash, enqueue_time, and rate_limit_applied boolean
Session Metadata Attachment at Capture Time
When a trigger (UI/Hotkey/API) includes metadata fields speaker, topic, tags (array) Then these fields are validated (speaker/topic <= 120 chars; each tag <= 32 chars; max 10 tags) and persisted on the capture record Given default session metadata exists When non-empty metadata is supplied on trigger Then supplied values override defaults for that capture only When a capture is viewed in the queue UI Then attached metadata is visible and searchable within 30 seconds of enqueue
Unified Capture Queue and Auditability
When captures are created from any trigger source Then they all appear in a single queue ordered by enqueue_time descending Each queue item stores required fields: capture_id, session_id, user_id, source, start_time, end_time, pre_roll_seconds, post_roll_seconds, enqueue_time, status, debounce_suppressed_count, metadata_hash For each trigger, the audit log records: timestamp (UTC ISO 8601), source, user_id, session_id, trigger_event_id, debounce_applied boolean, outcome (enqueued|suppressed|rejected) The queue and audit endpoints support filtering by user_id, source, time range, and status
Per-User Permissions and Trigger Enforcement
Given role-based permissions are configured When a user without capture permission attempts to use the UI button or hotkey Then the action is blocked, a tooltip or toast explains the restriction, and an audit entry with outcome='rejected' is written Given a token without capture:write scope calls the API trigger Then the request is denied with 403 and no capture is queued Given permissions are granted mid-session When the user retries the trigger Then the trigger succeeds without requiring app restart
Auto Pre/Post Stitch & Clean Cuts
"As a content editor, I want the captured highlight to start and end at natural points so that it feels professional and requires minimal manual cleanup."
Description

Automatically stitches the configured pre-roll with a post-roll segment after a trigger, producing a clean, context-rich highlight. Uses audio-aware word-boundary trimming, silence detection, and scene-cut detection to avoid mid-word or mid-frame cuts. Normalizes loudness, applies gentle crossfades as needed, and removes dead air within a small tolerance. Ensures frame-accurate, artifact-free outputs aligned with ClipSpark’s timeline model for downstream editing or immediate publishing.

Acceptance Criteria
Trigger Stitch with Configured Pre/Post Durations
Given pre-roll is set to P seconds and post-roll is set to Q seconds and a trigger occurs at time T When the clip is generated Then the clip starts at the nearest frame to (T − P) and ends at the nearest frame to (T + Q) And the clip duration equals P + Q within ±1 frame And audio and video timestamps are continuous with no gaps or overlaps at the join And the clip is available for playback/export within 3 seconds after the post-roll window completes
Insufficient Buffer Fallback for Pre-Roll
Given pre-roll is set to P seconds and the buffer contains only B seconds before trigger time T (B < P) When the clip is generated Then the clip starts at the nearest frame to (T − B) and ends at the nearest frame to (T + Q) And metadata includes preRollShortfall = P − B in seconds And the clip duration equals B + Q within ±1 frame
Audio-Aware Word-Boundary Trimming
Given word-level transcript alignment with start/end times is available and proposed cut points fall within words When trimming start and end Then cut points are shifted to the nearest word boundary or nonspeech segment within ±250 ms And no word in the transcript is truncated in the exported clip And join regions begin/end on zero crossings or use a 10–50 ms fade-in/out to avoid clicks
Frame-Accurate Scene-Safe Cuts
Given the proposed video cut points are computed When a scene change is detected within ±8 frames of a proposed cut Then the cut is adjusted to the scene boundary frame And all cuts occur on exact frame boundaries (no partial frames) And there are no duplicated or dropped frames across the join (PTS monotonicity preserved)
Silence Reduction Within Tolerance
Given the stitched segment contains nonspeech intervals where RMS < −50 dBFS and VAD = silence When producing the final clip Then any contiguous silence longer than 800 ms is reduced to 200 ms And no remaining silence segment exceeds 300 ms And total time removed by silence reduction does not exceed 5% of the clip duration And speech segments are not truncated (VAD = speech remains intact)
Loudness Normalization and Gentle Crossfades
Given the input audio loudness varies across segments When exporting the clip Then integrated loudness is normalized to −16 LUFS ±1 LU (stereo) or −19 LUFS ±1 LU (mono) And true peak does not exceed −1.0 dBTP And if RMS level difference across a join exceeds 2 dB, apply an equal-power crossfade of 50–150 ms And if difference is ≤ 2 dB, no crossfade is applied
Timeline Alignment and Branded Export Readiness
Given ClipSpark’s timeline model and a branding template are configured When the clip is generated Then startTimecode, endTimecode, sourceMediaId, fps, timebase, and per-cut mappings are written to a sidecar metadata file And seeking to 10 random positions in the exported clip maps to the source within ±1 frame And frame rate and resolution match project settings (no unintended resampling) And branding overlays are applied per template without obscuring content safe area And audio-video sync offset is ≤ 20 ms throughout the clip
Branded Clip Templates & Overlays
"As a marketer, I want captured highlights to include our brand elements automatically so that every clip is ready to share without manual design work."
Description

Applies workspace-defined branding automatically to captured highlights, including watermarks, intro/outro bumpers, lower-thirds, captions burn-in option, and call-to-action end cards. Supports multiple aspect ratios (16:9, 9:16, 1:1) and safe-area guides, with per-destination presets. Integrates with ClipSpark’s existing branding library and captioning engine to ensure consistent, on-brand outputs without extra steps.

Acceptance Criteria
Auto-Apply Workspace Branding to BackCapture Highlights
Given a workspace branding template is configured (watermark, intro/outro bumpers, lower-thirds, CTA end card, caption style) and a BackCapture highlight is created When the highlight clip is auto-generated Then the clip applies all configured brand elements automatically with no manual steps And the brand assets used are the latest versions from the workspace branding library at render time
Per-Destination Preset Application
Given per-destination presets exist for YouTube (16:9), TikTok (9:16), and Instagram (1:1) including overlay positions and caption burn-in settings When exporting a highlight using each destination preset Then the output uses the preset’s aspect ratio (YouTube 1920x1080, TikTok 1080x1920, Instagram 1080x1080) And overlay positions and sizes match the selected preset’s rules within ±2px And the caption burn-in setting (On/Off) matches the selected preset
Aspect Ratios and Safe-Area Compliance
Given a template supports 16:9, 9:16, and 1:1 with safe-area guides defined When previewing and exporting clips in each aspect ratio Then no overlay element (watermark, lower-third, captions, CTA) crosses the safe-area boundary in preview or final export And the editor shows toggleable safe-area guides that match the selected aspect ratio And exported resolutions are exactly 1920x1080, 1080x1920, and 1080x1080 with square pixels
Captions Burn-In and Style Consistency
Given timestamped captions are generated by the captioning engine and the template sets Burn-In = On with specified font, size, color, and background style When rendering a highlight clip Then burned-in captions align within ±100ms of the source caption timestamps And visual style matches the template (font family, size within ±1pt, color hex, background opacity within ±2%) And if Burn-In = Off, no text is burned and sidecar caption files (SRT and VTT) are attached to the export
Watermark and Lower-Third Placement Rules
Given a watermark asset and a lower-third template with in/out timing When rendering clips across supported aspect ratios Then the watermark scales to 6% of the shorter frame dimension and stays ≥24px from the nearest edges And the watermark maintains ≥12px separation from burned-in captions and lower-thirds in all aspect ratios And the lower-third appears at its configured times (e.g., T=3s in, T=8s out) with the template’s animation, without overlapping captions
Intro/Outro Bumpers and CTA End Cards Auto-Stitch
Given intro and outro bumpers and a CTA end card are configured in the branding library, and BackCapture has buffered pre-roll and post-roll When a moment is captured and the clip is auto-stitched Then the segment order is [intro bumper (if configured)] + pre-roll + moment + post-roll + outro bumper + CTA end card per template And transitions between segments match the template (e.g., cut or fade) with no blank or duplicate frames And the final duration equals the sum of configured segments within ±0.1s
Missing Asset Fallbacks and Error Reporting
Given one or more brand assets are missing or invalid at render time When rendering a clip Then the system applies workspace defaults or omits only the missing element per fallback rules without failing the export And a warning is recorded in the job details and surfaced in the UI, identifying the missing asset And if a critical asset (e.g., intro bumper or CTA) has no default, the export fails with a clear error message and retry guidance
Instant Render & Share Pipeline
"As a social media manager, I want captured highlights to be ready to share within seconds so that I can post while audience interest is highest."
Description

Delivers near-real-time processing of captured highlights via fast, parallelized encoding with hardware acceleration where available. Saves clips into the ClipSpark Library with tags, timestamps, speaker metadata, and summary snippets. Provides one-click export to common formats and direct publishing to configured destinations (e.g., YouTube Shorts, TikTok, Drive) with progress feedback and retry logic. Ensures consistent quality targets while keeping end-to-end turnaround under a few seconds for short clips.

Acceptance Criteria
Sub-30s Highlight Render Under 3 Seconds
Given a captured highlight of duration ≤ 30 seconds and hardware acceleration available When the user triggers Instant Render Then the pipeline (stitch + encode + mux + metadata + save) completes in ≤ 3.0 seconds at the 95th percentile across 100 runs And completes in ≤ 5.0 seconds at the 99th percentile And the output contains no dropped or duplicate frames (frame count and timestamps match source within ±1 frame) And visual quality meets or exceeds VMAF ≥ 85, SSIM ≥ 0.96, PSNR ≥ 38 dB And the brand overlay/preset is applied exactly as configured
Auto Metadata Save to Library
Given a rendered clip is saved to the ClipSpark Library Then the record includes: tags[], timestamps[] of key moments (≥ 1 for clips > 10s), speakerSegments with speakerId and time ranges covering ≥ 95% of clip duration, and a summary snippet 160–300 characters And all fields validate against the current Library schema And the item is searchable by tag, speakerId, and words in the summary within ≤ 2 seconds of save And createdAt, sourceVideoId, highlightTimeRange, and destinationIds[] are populated
One-Click Export to Common Formats
Given a rendered clip exists in the Library When the user selects Export and chooses any built-in preset [MP4 H.264 16:9 1920x1080 AAC 128 kbps, MP4 H.264 9:16 1080x1920 AAC 128 kbps, Audio-only MP3 128 kbps] Then the exported file matches the chosen preset’s container, codec, resolution/aspect, and bitrate And for clips ≤ 60 seconds, export time is ≤ 1.0x clip duration with hardware acceleration and ≤ 2.0x without And the exported filename follows {title}_{aspect}_{yyyyMMdd_HHmmss}.{ext} And a checksum (MD5 or SHA-256) is recorded and stored with the Library item
Direct Publish to Destinations with Retry
Given destinations are configured for YouTube Shorts, TikTok, and Google Drive When the user clicks Publish for a clip Then a job starts with stage-wise progress (encode, upload, process, publish) updated at least every 1 second And on transient failures (HTTP 5xx, timeouts, network errors) the job retries up to 3 times with exponential backoff (2s, 4s, 8s) and ±20% jitter And on client/auth/validation errors (HTTP 4xx) the job fails without retry and presents a clear, actionable error message And on success, the destination returns a share URL or ID which is stored on the Library item, and the post has the correct title, description containing the summary snippet, and hashtagified top 3 tags And publish requests respect platform constraints (aspect ratio, max duration); if violated, the job blocks before upload with a clear message
Parallelized Encoding Uses Hardware Acceleration
Given the host supports GPU/video acceleration (NVENC, Quick Sync, VideoToolbox, or AMF) When two highlights are rendered concurrently Then hardware acceleration is used for both streams (encoder reported by pipeline matches HW codec) with average encode throughput ≥ 2x realtime per stream at 1080p And if hardware acceleration is unavailable, CPU fallback is used with throughput ≥ 1x realtime per stream And no more than 4 concurrent encodes run by default; additional renders are queued FIFO And average CPU utilization remains ≤ 85% during render
Auto-Stitch BackCapture Pre/Post Roll
Given a BackCapture highlight with pre-roll and post-roll segments When Instant Render runs Then the output is a single clip with pre-roll and post-roll durations matching configuration within ±1 frame And cut points are frame-accurate with no duplicate or missing frames at boundaries And branded intro/outro and watermark template are applied per the selected preset And audio is continuous with crossfade at joins and no audible clicks (peak discontinuity < 1 dB)
Accurate Progress Feedback and ETA
Given a render or publish job is in progress When the user views the job status Then progress is shown per phase (stitch, encode, mux, save, upload, publish) with percentage updates at least every 500 ms And the ETA for any phase lasting ≥ 5 seconds has mean absolute percentage error ≤ 20% And terminal status (Success or Failed) is emitted within 500 ms of completion and includes a reason code on failure
Smart Auto-Trigger (AI Spike Detection)
"As a podcaster, I want the system to auto-catch exciting moments so that I don’t miss highlights when I’m focused on the conversation."
Description

Optionally monitors live audio/video signals and transcript streams to auto-trigger captures on notable events such as laughter, applause, keyword hits, sentiment shifts, or rapid engagement spikes. Provides tunable sensitivity, cooldown windows, and per-session keyword lists to reduce false positives. Logs rationale for each auto-trigger and allows quick undo to discard unwanted captures. Works alongside manual triggers without conflict.

Acceptance Criteria
Auto-trigger on Audience Reaction (Laughter/Applause)
Given auto-trigger is enabled with reaction_threshold=0.85, min_duration=0.5s, pre_roll=20s, post_roll=15s, cooldown=30s When the audio classifier detects laughter confidence >= 0.85 for >= 0.5s Then exactly one capture is created and includes the 20s pre-roll and 15s post-roll Given the same thresholds When applause confidence >= 0.85 for >= 0.5s Then exactly one capture is created with the configured pre-roll and post-roll Given cooldown=30s and a second qualifying reaction occurs within 30s of the previous trigger When detection conditions are met Then no second auto-trigger fires Given cooldown has expired When a new qualifying reaction occurs Then a new capture is created
Auto-trigger on Keyword Hit (Transcript Stream)
Given the per-session keyword list contains "breaking change" (case-insensitive), pre_roll=15s, post_roll=15s, cooldown=20s When the live transcript emits "Breaking change announced today" Then a capture is created with 15s pre-roll and 15s post-roll and the trigger reason is logged as keyword:"breaking change" Given cooldown=20s and the keyword occurs 3 times within 20s When detection conditions are met Then only the first occurrence triggers a capture Given the keyword list is empty When the transcript contains phrases not in the list Then no keyword-based auto-trigger fires
Sensitivity and Cooldown Controls Reduce False Positives
Given sensitivity_threshold=0.90 When an event scores 0.88 confidence Then no trigger occurs Given sensitivity_threshold=0.80 When the same event scores 0.88 confidence Then a trigger occurs Given cooldown is set to 10s When two qualifying events occur 12s apart Then two triggers occur Given cooldown is set to 30s When two qualifying events occur 12s apart Then only one trigger occurs Given a 10-minute test segment containing only non-event noise below threshold When monitoring runs across the segment Then zero auto-triggers are produced
Per-Session Keyword List Configuration
Given Session A adds keywords ["CTA", "enrollment"] When Session B starts Then Session B's keyword list is empty by default Given a session keyword list limit of 100 entries and max phrase length of 5 words When the user adds entries within limits Then they are accepted and applied immediately to detection Given the user attempts to add the 101st keyword When saving Then the UI blocks the save with validation "limit reached" and no changes are applied Given matching is case-insensitive and diacritics-insensitive When the transcript emits "EnrollMent" Then keyword "enrollment" matches Given the user removes "CTA" from the list When a transcript contains "CTA" Then no keyword-based auto-trigger fires for "CTA"
Trigger Rationale Logging and Transparency
Given a trigger occurs due to laughter with confidence 0.93 and threshold 0.85 When viewing the session's trigger log Then an entry shows timestamp, event_type="laughter", confidence=0.93, threshold=0.85, cooldown_remaining at trigger time, and a link to the produced clip Given a keyword-based trigger occurs for "breaking change" When viewing the log Then the entry includes the matched keyword and a 3-second transcript snippet around the match Given log export is requested When exporting Then all entries are emitted with ISO 8601 UTC timestamps and include session ID and clip ID Given a trigger is discarded via Undo When viewing the log Then the entry is marked status="discarded" with actor and timestamp
Quick Undo to Discard Unwanted Auto-Captures
Given an auto-trigger just created a capture When the user clicks Undo within 10 seconds Then the capture is deleted, no asset is published or exported, buffer resources are released, and the trigger entry is marked "discarded by user" Given the Undo window has expired When the user attempts to undo Then the action is unavailable and no changes occur Given an export job was queued for the auto-capture When the user clicks Undo within 10 seconds Then the export job is cancelled and no partial artifacts remain Given the capture list is refreshed When Undo has succeeded Then the clip is absent from the highlights list
Manual and Auto Triggers Coexist Without Conflict
Given an auto-trigger fired at t0 and a manual trigger is pressed at t0+2s while auto cooldown is active When both triggers are processed Then two distinct captures are created and saved with unique IDs; overlapping media segments are allowed without error Given manual trigger is pressed during auto-trigger cooldown When processed Then the manual trigger succeeds and is not blocked by cooldown Given a manual trigger occurs exactly as an auto-trigger fires When the system processes both events Then the system remains stable (no crash or deadlock) and both captures are created
RBAC, Privacy, and Ephemeral Retention
"As an admin, I want strict controls and automatic buffer disposal so that we protect sensitive content and meet our compliance obligations."
Description

Implements role-based access controls for who can enable BackCapture, trigger captures, and publish outputs. Keeps rolling buffers encrypted and ephemeral, discarding data automatically unless a capture is committed. Honors workspace retention policies, consent flags, and data residency constraints. Provides audit logs for trigger events and clip publication to support compliance and incident review.

Acceptance Criteria
RBAC: Enable BackCapture by Role
Given a workspace with roles {Owner, Admin, Editor, Viewer} and a project where BackCapture is disabled When a user with Owner or Admin role enables BackCapture via UI or API Then the request succeeds with HTTP 200/204, BackCapture is enabled for that project within 5 seconds, and an audit entry is recorded with actor, project, timestamp, method, and result=success And when a user with Editor or Viewer role attempts to enable BackCapture Then the request is denied with HTTP 403 and a user-facing message "Insufficient permissions", and an audit entry is recorded with result=denied
RBAC: Trigger Capture Permissions
Given BackCapture is enabled for a live session and the rolling buffer is active When a user with the "Capture:Trigger" permission clicks Capture or calls the Capture API with a properly scoped key Then the system commits the configured pre-roll and post-roll window and responds with HTTP 201 and a clip ID within 3 seconds, and the event is audited And when a user without the permission or an unscoped key attempts to trigger Then the system returns HTTP 403, no clip is created, and the denial is audited with actor, source, buffer window, and reason And triggers are rate-limited to 3 per user per minute per session; excess attempts return HTTP 429 and are logged
Publish Authorization and Consent Compliance
Given a draft clip exists with recorded consent flags for identifiable participants When a user with the Publisher role attempts to publish the clip Then publish succeeds only if required consent flags are satisfied by workspace policy; otherwise the request is blocked with HTTP 412 Precondition Failed and a list of missing consents And on success, the clip renders with the configured branding, contains the intended pre-roll and post-roll intervals, is available at a share URL, and an audit entry captures actor, clip ID, consent evaluation, branding profile, and destinations And when a non-Publisher attempts to publish Then the request is denied with HTTP 403 and logged
Encrypted Ephemeral Rolling Buffer
Given the BackCapture rolling buffer is active When storage and network are inspected via diagnostics Then buffer segments are encrypted in transit (TLS 1.2+) and at rest using workspace-managed keys; no plaintext buffer segments are written to disk or logs And buffer encryption keys are rotated at least every 24 hours and upon workspace key rollover And any API call to read buffer content requires "Buffer:Read" scope; unauthorized requests return HTTP 403 with no content bytes, and all attempts are audited
Auto-Discard Unless Committed
Given BackCapture is enabled with a 2-minute buffer duration When no capture is triggered Then buffer data older than 2 minutes is automatically purged and is not retrievable via API or backups And when a capture is triggered but canceled before commit Then no persistent clip is created and buffered data continues to rotate ephemerally And backups and DR snapshots exclude ephemeral buffer data; verification shows zero buffer objects in the backup catalog
Retention Policy and Data Residency Enforcement
Given a workspace retention policy of 30 days and data residency set to EU When a clip is committed and published Then the clip and derivatives are stored exclusively in EU-designated storage with cross-region replication disabled; storage location reports confirm region=EU And after 30 days without legal hold, the clip and derivatives are deleted, CDN caches are purged within 15 minutes, and deletion is recorded in audit logs with trace IDs And when legal hold is applied prior to expiry Then deletion is suspended until the hold is lifted; upon hold removal, deletion completes within 24 hours
Audit Logging for Triggers and Publications
Given audit logging is enabled by default When a capture trigger occurs or a clip is published Then an immutable, append-only audit record is written containing actor, action type, target ID, UTC timestamp, outcome, originating IP, client type (UI/API), and policy evaluations (RBAC, consent, retention) And audit records are queryable by Admins within 30 seconds and exportable in CSV and JSON with PII fields masked per workspace privacy settings And any attempt to modify or delete audit records via API is denied with HTTP 403 and the attempt is itself audited

Action Pings

Turn alerts into action with interactive notifications in Slack or Teams. Approve or snooze a marker, tag it, assign an owner, or publish a quick clip directly from chat—no tab switching. Impact: faster collaboration and zero-latency workflows while the stream is live.

Requirements

Slack & Teams App Integration
"As a team member who works in Slack or Teams, I want interactive ClipSpark pings where I already collaborate so that I can act on video events without switching tabs."
Description

Provide native app integrations for Slack and Microsoft Teams that deliver Action Pings as interactive messages. Use Slack Block Kit and Teams Adaptive Cards to render buttons and modals for Approve, Snooze, Tag, Assign, and Publish Clip. Implement OAuth 2.0 install and consent flows, bot users, required scopes/permissions, event subscriptions, and slash/command equivalents. Support multi-workspace/tenant linking to ClipSpark organizations and projects, message threading, channel and DM delivery, and uninstall/token revocation. Ensure reliable message rendering parity across platforms and handle regional/enterprise distributions.

Acceptance Criteria
OAuth Install and Consent for Slack and Teams
Given an org admin initiates installation for Slack or Teams from ClipSpark When the admin completes the provider’s OAuth/consent flow Then the app installs successfully, returns to ClipSpark with validated state parameter, and stores workspace/tenant IDs and tokens securely And only the documented minimal scopes/permissions are requested; the exact scopes/permissions granted are logged for audit And a bot user is created and can post a verification DM to the installer within 10 seconds And denial or partial consent aborts install, stores no tokens, and surfaces an actionable error message And token lifecycle is set up (refresh where applicable) and verified via a post-install health check And re-install rotates and replaces tokens without orphaning previous credentials
Interactive Action Ping Rendering Parity (Slack Block Kit and Teams Adaptive Cards)
Given a live stream marker triggers an Action Ping with actions Approve, Snooze, Tag, Assign, and Publish Clip When delivered to Slack (Block Kit) and Teams (Adaptive Cards) Then both platforms render all actions with consistent labels, tooltips/help text, and default states And opening any action presents a modal or equivalent interaction with required inputs and validation And action clicks are acknowledged within 2 seconds with an in-thread visual confirmation And payload sizes remain within each platform’s limits; oversized text is truncated with a “View in ClipSpark” link And accessibility requirements are met (text labels, focus order, and AA contrast) And schema validation passes against current Block Kit and Adaptive Cards versions; unsupported elements degrade with documented fallbacks
Perform Approve/Snooze/Tag/Assign/Publish from Chat Without Tab Switching
Given a user receives an Action Ping in Slack or Teams When the user clicks Approve Then the marker status updates in ClipSpark within 3 seconds and a confirmation reply is posted in the thread And repeated clicks are idempotent and produce no duplicate actions When Snooze is selected with 5m, 30m, 2h, or custom duration Then the ping reschedules accordingly and the new wake time is shown in-thread When Tag is used Then tags can be selected via autocomplete of project tags or created (if allowed) and are validated against naming rules When Assign is used Then the assignee can be chosen from the platform directory mapped to ClipSpark members; non-members prompt an invite flow link When Publish Clip is used Then a default-length clip is generated and a playable link is posted in-thread upon readiness And slash/command equivalents (e.g., /clipspark approve <id>) perform the same actions with identical validations and confirmations
Multi-Workspace/Tenant Linking to ClipSpark Orgs and Projects
Given an organization has multiple Slack workspaces or Teams tenants When an admin links a workspace/tenant to a ClipSpark organization and project Then the mapping (workspace/tenant ID → org/project) is persisted and visible in ClipSpark admin And per-channel overrides can map channels to specific projects And only ClipSpark org or project admins can create, update, or delete mappings And messages/actions are executed only for explicitly mapped workspaces/tenants/channels And unlinking a mapping stops deliveries within 60 seconds without uninstalling the app And changing a mapping preserves historical audit logs and message histories
Message Threading, Channel and DM Delivery Support
Given an Action Ping is triggered for a mapped project When delivered to a channel Then the parent message posts to the channel and all system updates (approve, snooze, publish) are added as thread replies When delivered to a DM Then only the recipient sees the ping; confirmations and errors are sent ephemerally to the actor And mentions resolve to valid platform entities and respect channel membership/permissions And rate limits are respected; retries use exponential backoff and deduplication to avoid duplicates And delivery success rate is ≥99.5% with median delivery latency ≤5 seconds And event subscription and slash/command endpoints respond with 2xx within 3 seconds to provider callbacks
Uninstall and Token Revocation Handling
Given the app is uninstalled from a Slack workspace or Teams tenant When an uninstall/revocation event is received Then all related tokens are revoked/erased within 60 seconds, event subscriptions are disabled, and mappings are marked inactive And no further messages are attempted; a health alert is raised to ClipSpark admins And reinstall creates fresh credentials and re-activation requires explicit admin confirmation And manual revocation in ClipSpark also revokes tokens at the provider and disables deliveries
Regional and Enterprise Distribution Readiness
Given an enterprise customer with regional or sovereign requirements installs the app When distributing to Slack Enterprise Grid or Microsoft Teams tenants Then admin approval workflows are supported and documented And data residency settings are honored; message metadata is stored only in the configured region And endpoints and auth flows support required regional constraints or clearly block with actionable guidance And required allowlists (domains/IPs) and TLS requirements are documented; webhooks serve TLS 1.2+ with SNI And platform reviews pass and listings include privacy/security disclosures And API deprecations are monitored; compatibility updates are released within 90 days of provider notices
Live Event Bridge (Sub‑Second Delivery)
"As a live producer, I want near‑instant pings when key moments occur so that my team can react and publish clips while the stream is live."
Description

Implement a real-time event pipeline that streams markers and alerts from live and processing sessions to Slack/Teams with sub‑second end‑to‑end latency and 99.9% delivery success. Use pub/sub with durable queues, webhooks, and backoff retries; preserve per-stream ordering using idempotency keys; de‑duplicate events; and provide back‑pressure controls. Support batching for low-priority events, fallback routing, and at‑least‑once delivery semantics. Include configuration for latency vs throughput trade‑offs and safeguards against rate limits/throttling by chat platforms.

Acceptance Criteria
Sub-second Delivery for High-Priority Live Markers
Given a live stream is emitting high-priority markers with server timestamps synchronized via NTP When each marker is published to the event bus and routed to the Slack/Teams adapter Then P95 end-to-end latency from marker creation to platform HTTP 2xx acknowledge is <= 1000 ms And P99 end-to-end latency is <= 1500 ms And no single high-priority event exceeds 2500 ms during a sustained 200 events/sec load with 1000 events/sec bursts for up to 10 seconds And latency metrics are recorded with trace IDs for 100% of events
99.9% Delivery with At-Least-Once and De-duplication
Given 100,000 mixed live and processing events over 60 minutes with 1% injected transient transport failures and one planned worker restart When the pipeline processes and delivers notifications Then >= 99.9% of events are delivered to at least one configured destination within 60 seconds of first attempt And at-least-once semantics are preserved (no acknowledged event is lost) And duplicates created by retries are suppressed at the adapter using idempotency keys (streamId + offset) within a 24-hour dedup window And durable queues persist undelivered events across restarts with zero data loss
Per-Stream Ordering Under Retry and Burst
Given a single stream produces events with monotonically increasing offsets and interleaved retries occur When events are delivered to the destination Then the destination receives events in offset order for that stream with no inversions And events from different streams may interleave without violating per-stream order And out-of-order retry arrivals are buffered or deferred to preserve order And ordering is verified by injecting out-of-order delivery attempts and comparing received offsets
Back-pressure and Rate-Limit Compliance
Given Slack/Teams return HTTP 429 with Retry-After and network latency spikes by 3x When sending events to those destinations Then the system honors Retry-After and applies exponential backoff with jitter And per-destination concurrency and QPS do not exceed configured limits And queue depth per tenant remains below the back-pressure threshold of 10,000 events with no high-priority drops And automatic degradation downgrades low-priority events to batch mode when thresholds are exceeded And rate-limit and back-pressure metrics and alerts are emitted within 30 seconds
Configurable Batching for Low-Priority Events
Given batching is enabled for low-priority events on a stream When events are accumulated for delivery Then batches contain no more than 50 events or 500 KB payload size, whichever occurs first And the max batch window is 250 ms; a flush occurs at window expiry And high-priority events bypass batching and remain single-message And P95 latency is <= 2000 ms for low-priority batched events and <= 1000 ms for high-priority events
Fallback Routing with Seamless Recovery
Given the primary destination (Slack) has sustained failures (>5% errors over 1 minute or outage >30 seconds) When attempting to deliver events Then events are routed to the configured fallback destination (e.g., Teams or generic webhook) with at-least-once guarantees And idempotency keys and per-stream ordering are preserved across failover And on recovery, routing returns to the primary within 60 seconds and missed deliveries are reconciled without duplicates And a failover and recovery status event is emitted and visible in metrics
Runtime Configuration and Observability
Given a tenant updates latency-vs-throughput settings (e.g., batching thresholds, concurrency limits, timeouts) via API or console When the update is saved Then new settings take effect within 60 seconds without process restarts And invalid inputs are rejected with validation errors and safe defaults are applied when optional values are omitted And logs include trace IDs, streamId, offset, idempotency key, delivery outcome, latency, retry count for 100% of events And dashboards expose P50/P95/P99 latency, delivery success rate, dedup rate, queue depth, retry counts, and rate-limit events per destination, with SLO burn alerts on breach risk
Chat Action Handlers (Approve/Snooze/Tag/Assign)
"As an editor, I want to approve, snooze, tag, or assign a marker directly from the ping so that the recording stays organized without opening ClipSpark."
Description

Create backend action handlers to process interactions from Slack/Teams messages and modals: Approve marker, Snooze with selectable durations, Apply existing tags, Create ad‑hoc tags, Assign owner, and Add notes. Persist updates in ClipSpark, synchronize state to the web app in real time, and return confirmations or actionable errors in the chat thread. Enforce idempotency, optimistic concurrency, and robust validation. Emit structured audit logs for each action and support localization of prompts and responses.

Acceptance Criteria
Approve Marker via Slack Message Action
- Given a valid Slack interactive payload (verified signature, unexpired timestamp) containing team_id, user_id, marker_id, and action=approve - When the user clicks Approve - Then the API responds 200 to Slack within 3s and updates marker.status=approved, marker.approved_by=user_id, marker.approved_at=current server time within 300ms of receipt - And then posts a threaded confirmation within 2s including marker_id and approved_at in the user's locale - And then disables or replaces the Approve action in the original message to reflect the new state - And if the marker is already approved, then the operation is a no-op and the thread message states "already approved" without duplicate side effects - And if the user lacks permission, then no state changes occur and a thread error is posted with error_code=forbidden and remediation text
Snooze Marker with Selectable Durations
- Given a Slack/Teams modal submission with marker_id and snooze_duration in {5m,15m,1h,1d} or custom_duration <= 7d - When the user submits Snooze - Then marker.snoozed_until is set to UTC time = now + duration and persisted within 300ms - And then a re-ping is scheduled for snoozed_until - And then a threaded confirmation is posted within 2s stating the resume time in the user's local timezone - And if custom_duration is invalid or >7d, then respond with validation error in the modal and no thread post, no state change - And if the marker is already snoozed beyond requested time, then no update occurs and a thread message indicates existing snooze_until
Apply Existing Tags and Create Ad-Hoc Tag
- Given a chat action with marker_id and tags=[existing_tag_ids] and new_tags=[string...] - When the user submits Apply Tags - Then all existing tags are linked, new_tags are created (name validated: 1-20 chars, letters/numbers/spaces, no duplicates by case-insensitive compare), and marker.tags is updated to a de-duplicated list (max 10) - And then a threaded confirmation is posted within 2s listing the final tag names - And if any tag name is invalid or quota exceeded, then no partial updates occur; the thread shows error_code=invalid_tag with the offending values and guidance - And all operations complete within 1s end-to-end for <=10 total tags
Assign Owner and Add Notes from Teams or Slack
- Given a Teams or Slack action with marker_id, assignee (user_id or verified email), and optional note (<=500 chars, Markdown limited to bold/italic/links) - When the user submits Assign - Then if the requester has editor or higher role, marker.owner_id is set to the resolved org member, and the note is saved with author, created_at, and sanitized Markdown - And then a threaded confirmation mentions the assignee (@user) and shows the first 140 chars of the note - And if assignee is not in the org, then no state changes occur and the thread shows error_code=unknown_user with an "Invite" deep link - And if note exceeds limits or contains blocked content, validation error is returned in-modal; no thread post; no state change
Real-Time State Synchronization to Web App
- Given any successful action that mutates a marker or its metadata - When the change is committed - Then a websocket event type=marker.updated is broadcast to subscribed web clients within 1s containing resource_id, version (monotonic), changed_fields, and actor_user_id - And then connected web clients reflect the change without a page reload; a test client receives the event exactly once per mutation - And when a client reconnects providing last_seen_version, then a resync endpoint returns missed changes so the client reaches the current version - And idempotent retries do not produce duplicate events (same version and idempotency_key)
Idempotency and Optimistic Concurrency Enforcement
- Given each chat action includes idempotency_key unique per UI submission - When the same action with the same idempotency_key is retried within 24 hours - Then no duplicate side effects occur and the response repeats the original outcome with idempotent=true - Given an update request includes version (If-Match) that does not equal the current marker.version - When the update is attempted - Then the API returns 409 Conflict with current_version and a retry hint; no mutations occur; a thread message indicates the conflict with an "Open in app" link
Structured Audit Logging and Localization of Responses
- Given any action attempt (success, failure, or no-op) - When processed - Then a structured audit log entry is written with fields: action_type, request_id, idempotency_key, actor_user_id, platform (slack|teams), workspace_id, resource_type, resource_id, previous_version, new_version, outcome, error_code (optional), timestamp (RFC3339), locale - And logs are persisted to durable storage and retrievable via an internal query within 5s - And prompts and thread responses are localized based on the chat payload locale with fallback to en-US; at minimum en-US, fr-FR, and es-ES translations exist - And if a message key is missing in the selected locale, an en-US string is used and a missing_translation warning is logged
One‑Click Publish Clip from Chat
"As a content manager, I want to publish a highlight clip directly from a chat ping so that we can share moments instantly while attention is high."
Description

Enable creation and publishing of highlight clips directly from an Action Ping. Use the marker’s timestamps and project template to auto‑generate a clip with captions and default in/out offsets; optionally open a modal for fine‑tuning trims, title, tags, and destination (library, share link, social connector). Queue rendering, post progress updates and the final link back to the message thread, and provide retry/cancel options on failure. Respect project export presets and branding policies.

Acceptance Criteria
One-Click Publish (Default Path)
Given an Action Ping in Slack or Teams with a valid marker and associated project template When the user clicks "Publish clip" without opening the modal Then the system uses the marker timestamps plus the project’s default in/out offsets to define the clip range and clamps to media bounds And applies the project’s caption settings to auto-generate captions for the range And enqueues a render job using the project’s active export preset And verifies the user has publish permission for the project; else posts a permission error in-thread and aborts And posts an acknowledgment in the original message thread with job ID and initial state And publishes the output to the project library by default And updates the thread with the final clip link upon completion
Fine-Tune and Publish via Modal
Given an Action Ping with a marker When the user selects "Fine-tune" from the Action Ping Then a modal opens pre-filled with: In, Out (from marker + default offsets), Title (from template/marker), Tags, and Destination options (Library, Share Link, Social connectors) And the form validates that In < Out, duration complies with preset min/max, and fields meet required formats And forbidden destinations (per policy) are disabled with an explanatory tooltip And on submit, the adjusted values are applied to the render payload and the job is enqueued And validation errors are shown inline without closing the modal; successful submit closes the modal with an in-thread acknowledgment And cancel closes the modal without creating a job
Threaded Progress Updates and Completion Link
Given a clip render/publish job initiated from chat When the job state changes to queued, rendering, uploading, or published Then the bot posts a single threaded update per state change including state name and percentage if available And updates remain in the original thread and do not create new parent messages And the completion update includes clip title, duration, destination, thumbnail preview, and a clickable link to the clip (and share link if selected) And if the job is skipped or superseded, the thread reflects the final terminal state with reason
Failure Handling with Retry and Cancel
Given a render or publish failure occurs for a chat-initiated job When the bot posts the failure update in-thread Then the message includes a human-readable error summary and "Retry" and "Cancel" actions And only the initiating user or a project admin can invoke Retry or Cancel; others see a permission error And selecting Retry re-enqueues the job with identical parameters and links the new job ID in-thread And selecting Cancel marks the job as canceled and prevents further processing And an audit record is written including user, action (retry/cancel), job IDs, timestamp, and error code
Enforce Export Presets and Branding Policies
Given project-level export presets (resolution, aspect, bitrate), caption style, and mandatory branding (logo/watermark/lower-third) When a user publishes a clip from an Action Ping (default or modal path) Then the render uses the current project export preset and caption styling without user override in chat And mandatory branding overlays are applied; any restricted fields are disabled in the modal with rationale And if a destination violates branding/policy rules, the option is blocked with an explanatory message And output filename and metadata follow the project’s naming template
Destination Selection and Permissions
Given the modal is open for publishing When the user selects a destination of Library-only, Share Link, or a configured Social Connector Then only destinations authorized for the project and user are selectable And selecting Share Link creates a link honoring project sharing policy (visibility, expiry) and posts it in-thread at completion And selecting a Social Connector publishes with stored credentials and posts the public URL in-thread upon success And if connector authorization is stale, the thread presents a re-auth link and the job waits until authorization completes or times out per policy, then fails with guidance
Cross-Platform Actions and Idempotency
Given an Action Ping is displayed in Slack or Microsoft Teams When the user clicks "Publish clip" or submits the modal Then interactive elements render and function correctly on the respective platform (buttons, dropdowns, modals) And duplicate submissions within a short window (e.g., repeated clicks or retries due to network) are idempotent and do not create duplicate jobs; only one job persists And the user receives a single acknowledgment with the surviving job ID And all timestamps and durations are computed consistently regardless of client locale
Notification Rules & Targeting
"As a project owner, I want to control which pings are sent and to whom so that the team sees only relevant, actionable notifications."
Description

Provide configurable rules that determine which events become Action Pings and who receives them. Support filters by keyword, speaker, sentiment, ML confidence, chapter, duration, and time window; routing by channel/DM, role, and team; quiet hours, rate limits, and digest mode. Offer a UI to preview rules against recent events, simulate volume, and test delivery. Allow per‑workspace and per‑project overrides with export/import of rule sets.

Acceptance Criteria
Create and route Action Pings with multi-filter rules
Given a workspace rule with keywords set to match any of ["deadline","action item"], speaker = "Host", sentiment ≥ 0.6, ML confidence ≥ 0.8, chapter = "Decisions", duration ≥ 10s, and time window 09:00–17:00 local time And routing targets set to Slack channel #live-notes and DM to @owner When an analyzed event satisfies all configured filters within the active window Then exactly one Action Ping is delivered to each configured target within 10 seconds of event detection And events that fail any single filter do not trigger a ping And keyword matching is case-insensitive and supports phrase boundaries And rule validation fails on save if any target is invalid or unreachable, with a specific error message
Enforce quiet hours and rate limits for real-time pings
Given quiet hours are configured 22:00–07:00 for the workspace time zone When events match a rule during quiet hours Then no real-time Action Pings are sent And matches are queued for the next digest or deferred delivery per rule setting Given a per-target rate limit of 10 pings per 60 minutes is configured When more than 10 matches occur for the same target within 60 minutes outside quiet hours Then only the first 10 are delivered in real time And excess matches are recorded as rate-limited with counts for inclusion in digest and audit logs And rate-limit windows reset precisely at the rolling 60-minute boundary, including across DST changes
Send scheduled digests with grouped Action Pings
Given digest mode is enabled daily at 08:00 and 17:00 in the rule’s time zone for targets #live-notes and @owner When at least one match occurs since the last digest Then a single digest message is delivered at the next scheduled time to each target And the digest contains total match count, top 5 highlights by confidence, and links to full context and clips And if there are zero matches, no digest is sent And rate-limited and quiet-hour-suppressed items are included in the digest with counts And digest delivery failures are retried up to 3 times with exponential backoff and surfaced in audit logs
Preview, simulate volume, and test delivery before activating a rule
Given a draft rule is configured but inactive When the user runs Preview against the last 7 days of events Then the system displays the exact set of events that would have triggered, with per-event reasons for match/non-match And Simulate Volume shows estimated per-hour and per-day counts based on the preview window When the user clicks Send Test Then a single clearly-labeled test Action Ping is delivered to the selected target(s) without persisting in analytics or digests And any missing permissions or invalid targets are surfaced before sending and block the test And enabling the rule after preview results in runtime matches consistent with preview on the same dataset
Apply per-workspace and per-project overrides with clear precedence
Given a workspace default rule set Rw and a project-level override Rp for Project A When an event originates from Project A Then Rp is used for evaluation, and any fields not specified in Rp inherit from Rw When an event originates from other projects Then Rw is used exclusively And the UI displays the effective rule after resolution, including inherited fields, for any selected project And disabling a rule at the project level prevents workspace-level delivery for that project while leaving others unaffected
Export and import rule sets with validation and safe changes
Given a workspace has rule sets defined When the user exports rules Then a versioned JSON file is generated containing all rule definitions, routing targets by external IDs, and metadata, excluding secrets When the user imports a rule file in Dry-Run mode Then schema and referential integrity are validated, conflicts are identified (add/update/delete), and a change plan is shown When the user confirms Apply with Merge strategy Then compatible rules are updated/added, conflicts resolved per chosen strategy, and a full audit entry is recorded And on any failure during import, all changes are rolled back and an error report is provided
Role/team targeting and channel/DM permissions are enforced
Given a rule targets role = "Reviewer", team = "Editing", Slack channel #live-notes, and DMs to assignees When an event triggers Then recipients are resolved at send time to current members of the role/team, and only users with app access receive DMs And messages to channels are delivered only if the app is a member of the channel; otherwise delivery is skipped with an audit warning And no Action Ping is sent to users outside the workspace or to archived channels And each recipient receives at most one ping per event even if they match multiple targeting criteria
Security, Auth, and Permissions Mapping
"As a security admin, I want chat actions to honor our org’s permissions and be auditable so that we meet compliance requirements."
Description

Secure chat-initiated actions with OAuth, short‑lived tokens, signed requests (Slack signing secret, Teams JWT), and CSRF protections. Map Slack/Teams identities to ClipSpark users via SSO/SCIM or verified email, and enforce project‑level roles and permissions on every action. Provide clear error messaging for denied actions, maintain a comprehensive audit trail (actor, resource, action, timestamp, origin), and support enterprise tenant isolation and data residency policies.

Acceptance Criteria
OAuth and Short‑Lived Token Security for Chat Integrations
- Given a Slack or Teams app installation, when the admin completes OAuth, then ClipSpark requests only the minimum required scopes, stores tokens encrypted at rest (FIPS-140-2 compliant), and associates the installation with a single tenant. - Given an installed integration, when a short‑lived action token exceeds its TTL of 10 minutes or is reused, then API calls are rejected with 401 and no state change occurs. - Given a token revocation event from Slack/Teams, when revocation is received or detected, then ClipSpark halts API usage within 60 seconds and flags the connection as disconnected in admin settings. - Given rotation policy, when tokens reach their rotation window, then refresh occurs without expanding scopes; failures surface an actionable reconnect prompt to tenant admins.
Signed Request Verification and CSRF Protection
- Given a Slack interactive request, when verifying the signature, then the X-Slack-Signature matches the HMAC-SHA256 of the raw body with the signing secret, the timestamp is within 5 minutes, and any replayed signature nonce is rejected; else respond 401 and perform no mutation. - Given a Microsoft Teams action, when validating the JWT, then issuer, audience, tenant, nbf/exp are verified against Microsoft OpenID configuration and current keys; invalid tokens return 401 with no state change. - Given any web callback or modal endpoint triggered from chat, when the CSRF token or state parameter is missing/invalid, then respond 403 and render a safe error message; valid tokens allow processing. - Given rate limiting, when >5 invalid signed requests are received from the same source within 1 minute, then temporarily block for 10 minutes and log a security event.
Identity Mapping via SSO/SCIM or Verified Email
- Given a Slack/Teams user initiates an action, when SSO subject or SCIM userId matches a ClipSpark user in the same tenant, then execute as that principal; else attempt verified email match constrained to the tenant; else deny with USER_NOT_MAPPED. - Given SCIM deprovisioning of a user, when deprovision completes, then chat-initiated actions by that user are denied within 15 minutes. - Given multiple candidate mappings (e.g., duplicate emails), when a conflict is detected, then no action is taken and an error instructs admins to resolve the conflict; successful mappings are unique and auditable. - Given a new user match via verified email, when first action occurs, then a pending link record is created and surfaced to admins for review (if policy requires) before enabling further actions.
Project‑Level Authorization for Chat Actions
- Given an action (approve marker, snooze, tag, assign owner, publish clip), when the mapped user lacks the required role on the target project, then the action is denied with 403 and no side effects occur. - Given a user with sufficient role, when the action is executed, then authorization is enforced server‑side and changes apply atomically; partial updates are rolled back on failure. - Given cross‑tenant references, when an action targets a resource outside the user’s tenant, then the request is blocked with 403 and no resource metadata is revealed. - Given role updates, when a user’s role changes, then authorization decisions reflect the change within 60 seconds for chat actions.
Clear Denial and Error Messaging in Slack/Teams
- Given any denied or failed action, when responding in chat, then an ephemeral message includes: reason code (AUTH_EXPIRED, PERMISSION_DENIED, USER_NOT_MAPPED, REGION_BLOCKED, INVALID_SIGNATURE), human‑readable explanation, a next‑step link, and a correlation ID. - Given a transient error (5xx or timeout), when the action fails, then a Retry button is shown for 15 minutes; upon retry, idempotency key prevents duplicate mutations. - Given localization settings, when the tenant locale is set, then error messages are returned in that locale with fallback to English if missing. - Given accessibility requirements, when messages are rendered, then they avoid color‑only distinctions and include descriptive alt text for buttons.
Comprehensive Audit Trail for Chat‑Initiated Actions
- Given any chat‑initiated action, when processed, then an immutable audit record is written capturing: actor_id, actor_origin (slack|teams), origin_ids (workspace/tenant, channel, message_ts), action, resource_type/id, prior_state, new_state, timestamp (UTC ISO‑8601), outcome (success|denied|error), correlation_id, ip, user_agent. - Given the admin audit UI/API, when queried by time range, actor, action, or resource, then matching records are returned within 2 seconds for up to 10k records and are exportable as CSV/JSON. - Given tamper resistance, when audit batches are committed, then a hash chain or signature is stored; any alteration is detectable via verification endpoint. - Given privacy policy, when rendering audit entries, then secrets/tokens are redacted and PII fields honor tenant data retention settings.
Tenant Isolation and Data Residency Enforcement
- Given a tenant with a configured data residency region (e.g., EU), when a chat action is executed, then all data storage and processing for that action occur within the region; cross‑region egress is blocked and logged. - Given a Slack workspace/Teams tenant bound to Tenant A, when a user attempts to act on a resource in Tenant B, then the action is denied with 403 and no identifiers or metadata of Tenant B are exposed. - Given a policy violation detection (e.g., attempted cross‑region write), when detected, then admins receive an alert within 5 minutes and subsequent actions are blocked until policy is restored. - Given regional failover testing, when simulated, then the system continues to enforce residency (no data leaves region) or cleanly degrades by denying actions with REGION_BLOCKED.
Delivery Observability and Admin Controls
"As an administrator, I want visibility into ping delivery and controls to fix issues so that collaboration remains reliable during critical events."
Description

Offer dashboards and APIs for monitoring Action Ping health: sent/delivered/interacted/failed counts, latency percentiles, error codes, and retry rates by workspace/channel. Provide tools to mute channels, pause delivery, rotate secrets, revoke installations, and re‑deliver failed messages. Generate alerts on anomaly detection and export telemetry to observability platforms. Surface in‑product health banners when integrations degrade.

Acceptance Criteria
Metrics Dashboard by Workspace/Channel
Given an admin views the Delivery Observability dashboard When they filter by workspace, channel, and time range (last 5m, 1h, 24h, custom) Then the dashboard displays sent, delivered, interacted, and failed counts for the selection And shows p50, p95, p99 end-to-end delivery latency for the selection And shows error code distribution and retry rate for the selection And all metrics refresh within 60 seconds of new events And totals match the underlying event store within ±1% for the selected window And users can export the visible dataset as CSV with the same filters applied
Observability API and Telemetry Export Integrations
Given an admin has a valid API token When they call GET /v1/action-pings/metrics with filters (workspace_id, channel_id, from, to, group_by) Then the API responds 200 with JSON including counts, latency_percentiles {p50,p95,p99}, error_codes[], retry_rate, and ISO 8601 UTC timestamps And supports pagination via limit and next_cursor; rate limited at 60 requests/min with 429 + Retry-After And unauthorized or expired tokens receive 401 with no metric data And returned values match the dashboard within ±1% Given an admin configures a telemetry export destination When they set up OTLP (gRPC/HTTP) or Datadog/Splunk/New Relic with credentials and test the connection Then delivery telemetry (counts, histograms, error codes, retries) exports with ≤60s lag And export failures are retried with exponential backoff (5 attempts) then sent to DLQ with alerts And disabling export stops transmission within 2 minutes and is audit logged
Channel Mute and Delivery Pause Controls
Given an admin with Manage Integrations permission When they mute a specific channel with reason and duration Then new Action Pings to that channel are suppressed for the mute duration And muted events are logged with scope, actor, reason, start, end in the audit log And unmuting resumes delivery and queued messages are sent in order When they pause delivery at the workspace level Then no messages are sent until resumed and send attempts return 503 with code delivery_paused And resuming re-enables delivery within 60 seconds
Secret Rotation Without Downtime
Given an integration uses a secret (token/webhook) When an admin initiates rotation Then the system supports dual-secret validation for up to 24 hours And deliveries succeed using either secret during the overlap window And the old secret can be revoked immediately or scheduled; revocation happens at the specified time And post-revocation requests with the old secret fail with 401 code secret_revoked And all rotation actions are audit logged with actor, timestamp, and target integration
Re-deliver Failed Messages Idempotently
Given failed Action Pings are visible in the dashboard/API for a time range When an admin triggers re-delivery for a single message or a filtered set Then only messages with last_status=failed are retried And retries respect current mute/pause settings and workspace rate limits And each retry uses an idempotency key to prevent duplicates in Slack/Teams And exponential backoff applies (up to 3 attempts) unless an admin overrides with a one-time immediate retry And the system reports per-message outcomes and error codes after re-delivery completes
Revoke Integration Installation and Access
Given an installed Slack or Teams integration When an admin revokes the installation for a workspace or channel Then access tokens/webhooks are invalidated within 2 minutes And pending outbound deliveries to the revoked scope are canceled with error code integration_revoked And subsequent send attempts receive 403 integration_revoked And the revoke event is audit logged with actor, scope, and timestamp And re-installation creates new credentials and does not restore revoked secrets
Anomaly Alerts and In-Product Health Banners
Given baseline metrics for the last 7 days When failure rate exceeds max(5%, 3x baseline) for 5 consecutive minutes or p95 latency > 2s for 5 consecutive minutes Then an anomaly is created and alerts are sent to configured channels (email, Slack, webhook) within 2 minutes And alerts include scope (workspace/channel), metric, magnitude, timeframe, and a runbook link And acknowledgements, mute (with duration), and resolve actions are available and audit logged And the product displays a health banner to affected users within 60 seconds showing impact, start time, latest update, and link to details And repeated alerts are suppressed by a 30-minute cool-down per scope/metric unless severity escalates

Momentum Heatmap

Watch a live timeline glow with intensity layers for sentiment, keywords, and speaker emphasis. Post-event, jump to peaks, compare segments, and export a highlight reel from the heatmap in one pass. Value: triage hours of content in minutes using a visual map of the most quotable moments.

Requirements

Real-time Heatmap Rendering Engine
"As a knowledge worker reviewing long recordings, I want a live, layered timeline that stays in sync with playback so that I can visually spot important moments without scrubbing manually."
Description

Implements a performant, layered timeline visualization synchronized with video playback that renders intensity bands for sentiment, keywords, and speaker emphasis in real time. Supports streaming updates during recording or upload processing, smooth zoom/pan, tooltip readouts, and a responsive layout for long-form content (up to multi-hour sessions). Provides layer toggles, color legends, and opacity controls to help users triage visually. Integrates with ClipSpark’s player events and transcript timecodes via a standardized metrics API (WebSocket for live, REST for post-event) and caches computed bins for instant scrubbing. Includes accessibility (high-contrast palettes, keyboard navigation), error handling, and graceful fallbacks when a layer is unavailable.

Acceptance Criteria
Live Layer Rendering Latency and Stability
Given the video is playing and metric updates stream over WebSocket at up to 10 events/sec per layer, When an update is received, Then the corresponding intensity band renders within 200 ms end-to-end and the visible frame rate remains at least 50 FPS, not dropping below 45 FPS for more than 100 ms. Given simultaneous updates for sentiment, keywords, and speaker emphasis arrive out of order, When the engine processes them, Then they are ordered by timestamp before rendering with no temporal overlap artifacts. Given a continuous 15-minute live session, When updates stream without interruption, Then the engine renders all updates with less than 1% drop rate and without visual freezes longer than 100 ms.
Accurate Timecode Sync During Scrub and Rate Changes
Given playback is active, When the user seeks or scrubs to any position, Then the heatmap cursor and active-bin highlight align with the player currentTime within ±50 ms. Given the playback rate changes between 0.5x and 2.0x, When playback continues, Then the heatmap remains synchronized within ±50 ms for the duration of playback. Given the user performs rapid scrubbing across the entire timeline, When scrubbing stops, Then the heatmap re-renders the correct region within 100 ms with no blank tiles or placeholder gaps.
Smooth Zoom/Pan and Responsive Layout for Multi-hour Timelines
Given a timeline up to 8 hours, When the user zooms from full duration to a 30-second window, Then the transition completes within 250 ms and maintains at least 50 FPS during the animation. Given the user pans a zoomed view by dragging, When the viewport moves, Then input-to-render latency stays under 100 ms and the heatmap tiles stream in without visible pop-in. Given viewport widths from 320 px to 2560 px, When the page is resized, Then the heatmap remains fully usable (no horizontal overflow, labels readable) and interactive targets remain at least 32 px touch size.
Layer Toggles, Legends, and Opacity Controls
Given the layer toggles for Sentiment, Keywords, and Speaker Emphasis, When a user toggles any layer, Then visibility updates within 100 ms and the setting persists for the session. Given the opacity control for any visible layer, When the user adjusts opacity from 0% to 100% in 10% increments, Then the visual intensity changes immediately and remains perceptually linear across the range. Given the color legend is displayed, When a user focuses or hovers it, Then it shows the scale, units, and min/max values for the active layer and meets high-contrast mode requirements with a contrast ratio of at least 4.5:1.
Tooltips and Keyboard/Screen Reader Accessibility
Given keyboard focus or mouse hover over the heatmap, When a bin is targeted, Then a tooltip appears within 100 ms showing timestamp (HH:MM:SS), sentiment score (−1.0 to +1.0), top keywords with counts for the bin window, and speaker label with emphasis score. Given the timeline has keyboard focus, When the user presses Left/Right Arrow, Then the cursor moves by 1 second; when Shift+Arrow is pressed, it moves by 10 seconds; Home/End jump to start/end; Enter toggles the focused layer. Given a screen reader user, When navigating the timeline, Then ARIA roles/labels announce the focused time and layer value, and all controls (toggles, opacity, legends) are reachable in a logical tab order with visible focus indicators.
Streaming and Post-event Data Integration with Graceful Fallbacks
Given a live session, When the WebSocket connection is established, Then metric updates are applied in real time; if the connection drops, it retries with exponential backoff (max wait 30 s) and shows a non-blocking reconnect indicator. Given a post-event session, When the timeline loads, Then the engine fetches metric bins via REST in paginated chunks sized to the viewport and prefetches adjacent pages to cover ±30 s beyond the viewport within 300 ms. Given any single layer fails to load or returns an error, When rendering proceeds, Then remaining layers continue to render and an inline "Layer unavailable" state with a retry action is shown for the failed layer without blocking playback.
Cached Bin Tiles Enable Instant Scrubbing
Given a 3-hour recording has loaded once, When the user scrubs continuously from start to end, Then 95% or more of heatmap tile requests are served from cache and no loading spinners appear within the viewport. Given the user releases the scrubber at a new position, When the viewport settles, Then the heatmap completes render of the visible window within 80 ms using cached bins. Given cache capacity limits, When the cache exceeds its 150 MB budget, Then least-recently-used tiles are evicted and future scrubs still meet the 80 ms render target for the current viewport.
Low-latency Sentiment Analysis Layer
"As a podcaster, I want to see where sentiment spikes occur on the timeline so that I can jump to emotionally resonant clips for highlights."
Description

Generates and displays per-interval sentiment scores (e.g., negative/neutral/positive) aligned to transcript tokens with sub-second latency for live sessions and higher-accuracy recalculation post-event. Applies smoothing and calibration to reduce noise, supports multilingual transcripts, and exposes confidence values for UI de-emphasis when uncertain. Streams incremental bins to the rendering engine and persists finalized results to the session record for quick reloads. Provides configuration for window size and scale, and integrates with existing ASR/transcription pipeline to avoid duplicate processing.

Acceptance Criteria
Live Sentiment Streaming Latency and Alignment
Given an active live session receiving ASR tokens with timestamps When the sentiment layer processes tokens and emits sentiment bins Then the median latency from token end_time to bin emission is <= 800 ms And the p95 latency is <= 1500 ms And each bin includes start_time and end_time aligned to underlying token boundaries within ±100 ms And bins are published incrementally in chronological order via the designated renderer streaming interface
Post-Event Recalculation and Persistence
Given a completed session with provisional live sentiment bins When the post-event high-accuracy recalculation is triggered Then finalized sentiment bins are produced for the entire session with confidence values And finalized bins replace provisional bins in persistent session storage And the persisted record can be loaded and returned via the API in <= 300 ms for a 2-hour session metadata-only request And each finalized bin includes a model_version and finalized=true flag
Smoothing and Calibration Controls
Given smoothing window_size=W and calibration thresholds Tneg<Tpos When the sentiment layer processes an input segment with rapid polarity changes Then the output polarity flips no more than 2 times within any 5-second window And the effective additional lag introduced by smoothing is <= (W/2 + 150 ms) And raw scores are mapped to Negative/Neutral/Positive using Tneg and Tpos deterministically And updating W, Tneg, or Tpos via the configuration API takes effect within 2 seconds without restarting the session
Confidence Exposure for De-Emphasis
Given a generated sentiment bin When the bin is emitted to the renderer stream and persisted Then the bin payload includes confidence in [0.0,1.0] with three-decimal precision And bins with confidence < 0.60 include uncertain=true And bins with confidence >= 0.60 include uncertain=false And confidence values are preserved unchanged between streaming and persisted records
Multilingual and Code-Switch Support
Given transcripts tagged as English, Spanish, or French within a single session When the sentiment layer processes segments per language tag Then language-appropriate models are selected automatically for each segment And code-switched segments are scored using the correct segment language And segments with unsupported language tags are emitted with label='unsupported_language' and confidence=0.0 without causing processing failures
Configurable Window Size and Sentiment Scale
Given configuration options window_size (0.2s to 5.0s) and scale (categorical or continuous) When a client updates these options via the configuration API during an active session Then subsequent emitted bins reflect the new window_size and scale within 2 seconds And invalid configurations are rejected with 400 and a descriptive error And default workspace-level configuration is applied automatically to new sessions
Integration with Existing ASR Without Duplicate Processing
Given an existing ASR pipeline emitting token text and timestamps When the sentiment layer is enabled for a session Then the sentiment service consumes ASR outputs from the shared interfaces and does not invoke ASR endpoints directly And no additional ASR jobs are created in system logs for the session And the average ASR processing time per token remains within ±5% of baseline (sentiment disabled)
Keyword Intensity & Custom Tracking
"As an educator, I want to track specific concepts across a lecture so that I can quickly find the most concentrated, quotable moments for those topics."
Description

Computes and visualizes keyword density over time using transcript tokens and NER, with support for user-defined tracked terms, stemming, and synonyms. Offers weighting and threshold controls, and displays top terms on hover for the hovered region. Enables quick filtering of the heatmap to one or more tracked concepts and persists custom term lists per workspace. Pre-indexes transcripts for fast recomputation and exposes a search-to-heatmap link so results can be highlighted on the timeline.

Acceptance Criteria
Baseline Keyword Density via Tokens and NER
Given a processed transcript with aligned token timestamps and named entities When the Momentum Heatmap renders with default settings Then each time bin’s intensity is proportional to the count of keyword occurrences whose timestamps fall within that bin as per the configured bin size And named entities are included as keywords and attributed to the correct time bins And the total count summed across bins equals the total counted occurrences in the transcript (±0 difference) And rendering completes without errors for transcripts up to 4 hours
User-Defined Tracked Terms with Stemming and Synonyms
Given a user adds tracked terms with stemming enabled and a synonym list When the transcript contains morphological variants and synonyms of those terms Then all variants and synonyms are aggregated under their parent tracked term in counts and visualization And toggling a tracked term on or off immediately includes or excludes its contribution from the heatmap And tracked terms accept case-insensitive input and support multi-word phrases And removing a tracked term removes its effects and the term no longer appears in suggestions
Weighting and Threshold Controls Affect Heatmap
Given term weights are set via UI (default weight 1.0) and a visibility threshold slider is available When a user adjusts a term’s weight Then the affected bins’ intensities update within 300 ms without full timeline re-render And when the visibility threshold is increased Then bins with aggregate intensity below the threshold are hidden and those at or above remain visible And resetting weights and threshold restores the default visualization
Hover Displays Top Terms for Timeline Region
Given the heatmap is visible When the user hovers over a heatmap region for at least 150 ms Then a tooltip appears showing the top 5 terms for that region sorted by intensity with counts and percentage of region total And tracked terms are visually distinguished with a badge indicator And moving the pointer to an adjacent region updates the tooltip within 150 ms And the tooltip disappears when the pointer leaves the heatmap region
Filter Heatmap by One or More Tracked Concepts
Given at least one tracked term exists When the user applies a filter selecting one or more tracked terms Then only bins containing any of the selected concepts remain highlighted and all others are dimmed to 20% opacity or less And selecting or deselecting terms updates the visualization within 300 ms And clearing the filter restores the unfiltered heatmap within 300 ms
Workspace-Persistent Custom Term Lists
Given a workspace and a user with permission to edit term lists When the user creates or updates a named custom tracked term list Then the list is saved to the workspace and is available in subsequent sessions for all workspace members within 5 seconds of save And switching projects within the same workspace shows the same list And deleting a list requires confirmation and removes it from all projects in that workspace
Pre-Indexing Performance and Search-to-Heatmap Linking
Given transcripts have been pre-indexed after upload or ingest When a user toggles term filters, adjusts weights, or adds or removes a tracked term Then the heatmap recomputes and updates within 700 ms for recordings up to 2 hours And when a keyword search is performed and the user clicks "Show on Heatmap" Then all matches are highlighted on the timeline within 300 ms, and the count of highlighted bins equals the number of matched timestamp ranges mapped to bins (±0 difference) And clearing the search removes the highlights
Speaker Emphasis Detection
"As a producer, I want to see when any speaker becomes particularly animated so that I can identify engaging moments faster."
Description

Derives an emphasis score per interval by combining prosody features (volume, pitch variance, speaking rate) with textual cues (intensifiers, exclamations) and speaker diarization. Normalizes by speaker to avoid bias and supports multi-speaker sessions common in panels and lectures. Renders a distinct emphasis layer and allows per-speaker isolation to see who drove peaks. Integrates with existing diarization outputs and caches feature vectors for reuse in other analytics.

Acceptance Criteria
Compute Emphasis Scores per 500ms Interval
Given a processed long-form video with aligned transcript and diarization available When the emphasis detector runs with default settings (frame=500ms) Then it outputs a deterministic emphasis score between 0.0 and 1.0 for every 500ms interval covering all spoken segments and silences And the score is a weighted combination of prosody (RMS volume, pitch variance, speaking rate) and textual cues (intensifiers, exclamations), with weights logged in metadata And on the held-out validation set (≥10 videos, ≥3 speakers each), the Pearson correlation between model scores and human-labeled emphasis ratings is ≥ 0.6 and ROC-AUC for classifying top-20% emphasis intervals is ≥ 0.80 And repeated runs on the same inputs yield identical scores (variance = 0)
Speaker-Normalized Emphasis Scoring
Given a session with ≥2 speakers with different baseline loudness When per-speaker normalization is applied Then each speaker’s score distribution over their own speech has mean within ±0.1 of 0 and standard deviation within ±0.1 of 1 And in a synthetic test where both speakers contain identical emphasis events but different baseline volumes, the share of top-5% emphasis intervals attributed to each speaker differs by ≤ 10% from their share of speaking time
Diarization Integration and Overlap Handling
Given an existing diarization JSON with speaker labels and timestamps, including overlapping speech When emphasis is computed Then every 500ms interval within speech is assigned to one or more active speaker IDs; non-speech intervals are marked as "silence" And for overlapping speech, separate per-speaker scores are emitted without dropping frames; interval-level assignment accuracy vs the diarization reference is ≥ 99% And no intervals are left untagged or assigned to invalid speaker IDs
Per-Speaker Isolation Layer Rendering
Given a processed session in the Momentum Heatmap UI When the user toggles the Emphasis layer and selects/deselects individual speakers Then only the selected speakers’ emphasis traces render, with non-selected hidden And hovering a point shows timestamp, speaker ID, and score with ±100ms alignment to playback And applying a speaker filter updates the timeline within 200ms for a 60-minute session on recommended hardware And the selection persists via URL state and is restored on page reload
Peak Detection and Jump-to-Playback
Given computed emphasis scores When the user enables “Show Peaks” with parameters (top N, min-separation=5s, speaker filter optional) Then the system identifies local maxima satisfying the parameters and lists them in descending score And clicking a peak starts playback within ±150ms of the peak time with a 2s configurable lead-in And peaks respect speaker filters and diarization boundaries (no peaks assigned to excluded speakers)
Feature Vector Caching and Invalidation
Given a session processed once When re-running emphasis detection without changes to audio, transcript, or diarization Then cached prosody and text feature vectors are reused, reducing feature extraction time by ≥80% compared to a cold run And when the transcript or diarization changes (hash mismatch), only affected intervals are recomputed and cache entries invalidated accordingly And cache storage exposes metrics: hit rate, size, and last-access time per session
Peak Detection & Jump-to Navigation
"As a content editor, I want to jump directly between the highest-impact moments so that I can triage hours of content in minutes."
Description

Detects local maxima across sentiment, keyword intensity, and emphasis layers and computes a composite momentum score to rank moments. Deduplicates adjacent peaks via hysteresis and minimum-gap rules to avoid clutter. Adds clickable peak markers, a mini-map navigator, and keyboard shortcuts (next/previous peak). Provides sensitivity controls and a filter to show peaks by layer or composite. Exposes a peak list with timestamps for quick auditing and integrates with player to auto-seek on selection.

Acceptance Criteria
Detect Peaks Per Layer
Given a processed recording with sentiment, keyword intensity, and emphasis signals aligned to timeline timestamps When the peak detection job executes Then local maxima are identified on each layer using the configured window and threshold And each peak is recorded with start, apex, and end timestamps at ≤100 ms precision And peak counts and apex locations are deterministic across repeated runs on the same input And peaks outside media duration are not produced
Composite Momentum Scoring and Ranking
Given normalized per-layer scores for detected peaks and a weight configuration When the composite momentum score is computed Then each composite score is a weighted combination in the range [0,1] And changing weights updates the ranking in real time without page reload And ties in composite score are resolved by earlier apex timestamp And the top N peaks are returned when a limit N is applied
Peak Deduplication via Hysteresis and Minimum Gap
Given peaks whose apexes are closer than the configured minimum gap X seconds When deduplication runs Then no two remaining peaks on the same layer have apexes closer than X seconds And merged peaks retain the highest composite apex and correct start/end bounds And with hysteresis H applied, flat/plateau regions yield a single peak within the H band And disabling deduplication produces all raw local maxima
Interactive Peak Markers and Keyboard Navigation
Given visible peak markers on the timeline When a user clicks a marker Then the player seeks to the peak apex within 200 ms and starts playback And the selected marker is visually highlighted and announced for accessibility Given assigned keyboard shortcuts for Next Peak and Previous Peak When the user presses the Next Peak shortcut Then focus and playback jump to the next visible peak by the active sort order And pressing the Previous Peak shortcut jumps to the previous visible peak
Mini-Map Navigator
Given the mini-map is displayed When the user drags the mini-map viewport or clicks a mini-map peak Then the main timeline scrolls/zooms accordingly and the player seeks to the selected position And mini-map and main timeline stay in sync during playback and on window resize And toggling mini-map visibility does not alter peak detection results
Sensitivity Controls and Layer/Composite Filtering
Given sensitivity controls and layer/composite filters are available When the user adjusts a sensitivity slider Then the visible peaks update within 200 ms without a full recompute of unchanged layers And when the user filters to a specific layer, only that layer’s peaks are shown and navigable And when composite is selected, only composite-ranked peaks are shown And resetting filters restores the prior multi-layer view
Peak List with Timestamps and Player Integration
Given a peak list panel is open When peaks are detected Then the list shows each peak with timestamp, layer, and composite score, sorted by the active sort And clicking a list item seeks to the peak apex within 200 ms and highlights the corresponding marker And the list supports keyboard navigation and reflects filter and sensitivity settings And timestamps are displayed in HH:MM:SS.mmm and copy correctly to clipboard
Segment Comparison View
"As a course designer, I want to compare candidate segments side-by-side so that I can choose the most impactful excerpt for my lesson."
Description

Enables selection of two or more time ranges to compare side-by-side with synchronized playback and overlaid heatmap metrics (sentiment, keywords, emphasis). Displays summary stats (peak count, average momentum, top terms) and supports saving named comparisons to a project. Provides drag-to-select from the heatmap, a compare panel, and shareable links for collaborators. Optimized for post-event analysis to validate which segment is most quotable or instructional.

Acceptance Criteria
Drag-to-Select Multiple Segments from Heatmap
Given a video is loaded and the Momentum Heatmap is visible And the Compare panel is open When the user drags across the heatmap to select a range Then a segment is created with start and end timestamps matching the selection within ±1 frame And the segment appears in the Compare panel with a label and its duration When the user performs an additional drag selection Then a second segment is added without removing the first And the UI allows at least 6 concurrent segments And selections with start >= end are rejected with an inline error And any selection shorter than 1.0 seconds is rejected with an inline error
Synchronized Side-by-Side Playback Controls
Given two or more segments exist in the Compare panel When the user presses Play Then all segment players start within 120 ms of each other And playback position is synced relative to each segment's start time When the user pauses, seeks, or scrubs in any segment Then all segments reflect the same relative playback position within 150 ms And changing playback speed between 0.5x and 2x maintains sync within 200 ms When one segment reaches its end before others Then it shows an "Ended" overlay while other segments continue playing
Overlay Heatmap Metrics on Each Segment
Given the compare view is active with at least two segments When the user toggles Sentiment, Keywords, or Emphasis overlays Then the selected overlays appear on each segment with a consistent legend And tooltips display timestamp and metric value on hover or keyboard focus And overlay rendering completes within 500 ms after toggle on a 60-minute video And metrics align to the segment's local timebase with 00:00 at segment start
Summary Stats Panel per Segment
Given the compare view has segments selected Then each segment shows Peak Count, Average Momentum, and Top Terms (up to 5) derived from the same data as the Momentum Heatmap And values match the underlying metric data for the selected time range (exact match for counts; averages within ±0.01) And Top Terms are ordered by frequency descending with ties broken by most recent occurrence And hovering a metric highlights the corresponding positions on the overlay
Save Named Comparison to Project
Given two or more segments are selected When the user clicks Save Comparison and enters a name Then the comparison is saved to the current project with segments, metric overlay toggles, and playback speed And the name is required, 1–100 characters, and unique within the project (case-insensitive) And the saved comparison appears in the project's Comparisons list within 1 second When the user renames or deletes the comparison Then changes persist across reload and are visible to project collaborators with edit access
Shareable Link for Collaborators
Given a saved comparison exists When the user copies a Share link Then the link opens the comparison view with the same segments and overlay toggles for any collaborator with project access And users without access see a Request Access screen and no segment data And opening the link loads the comparison and metrics in under 8 seconds for a 2-hour 1080p video over a 20 Mbps connection
Scalability and Responsiveness for Long Videos
Given a single video up to 3 hours in length and up to 8 selected segments Then UI interactions (drag-select, toggle overlays, open compare panel) respond within 250 ms in 95% of actions on Chrome 125+ with a 4-core CPU and 8 GB RAM And memory usage of the compare view stays below 700 MB in the browser after loading overlays And dropped frames do not exceed 5% at 1x playback during synchronized playback
One-click Highlight Reel Export
"As a marketer, I want to export a reel of top moments in one pass so that I can publish shareable clips without manual editing."
Description

Creates a highlight reel directly from selected peaks or the composite momentum ranking with configurable rules (clip length, lead-in/out, min gap, max number of clips). Auto-generates captions, optional lower-thirds, and transitions, and supports brand templates. Integrates with ClipSpark’s existing clip generation and export pipeline (MP4, social presets) and saves reels to the media library with metadata (source timestamps, layers used). Provides an undoable, idempotent operation so users can iterate quickly.

Acceptance Criteria
Manual Peak Selection Export
Given a video is loaded in Momentum Heatmap and the user has multi-selected one or more peaks When the user clicks "Export Highlight Reel" Then a candidate clip list is created containing exactly the selected peaks in the order shown in the UI And the export source is labeled "Manual Peaks" in the reel metadata
Auto-Select by Composite Momentum Export
Given a video with a computed momentum heatmap and no manual peak selections And the user has set Max Clips to M When the user chooses "Auto from Momentum" and clicks "Export Highlight Reel" Then the system selects the top M non-overlapping peaks by composite momentum score across the full timeline And ties in score are broken by earlier timestamp And the export source is labeled "Composite Momentum" in the reel metadata
Rule Application and Timeline Assembly
Given a candidate clip list and configured rules: Clip Length=L seconds, Lead-in=a seconds, Lead-out=b seconds, Min Gap=g seconds, Max Clips=M When the reel timeline is built Then each clip's in-point equals max(0, peak_start - a) and out-point equals min(source_end, peak_end + b) And adjacent clips with gap < g are merged into a single continuous segment And the final number of clips does not exceed M; if more remain, the lowest-momentum segments are dropped until M And all clip in/out timestamps align to frame boundaries (±1 frame) And clips are ordered chronologically
Auto-Captions and Optional Lower-Thirds
Given speech is present in the source audio When the reel is exported Then captions are auto-generated for 100% of audible speech within the reel with per-cue timing accuracy within ±200 ms And captions are attached as a sidecar (.srt) and are burned-in only when the chosen preset requires burned captions And if "Lower-thirds" is enabled, each clip displays a lower-third with speaker name (if available) for the first 3 seconds, styled per the selected template, and omitted when metadata is missing
Brand Templates and Transitions
Given the user selects a brand template T and a transition type X with duration d milliseconds When the reel is exported Then the rendered video uses template T fonts, colors, watermark/logo, and safe-area margins And the specified transition X of duration d is inserted between clips (not before the first or after the last) And the number of transitions equals (number of clips - 1) And if no template is selected, the default ClipSpark template is applied; if no transition is selected, hard cuts are used
Export Pipeline and Social Presets
Given the user selects an export preset P from [MP4-1080p (16:9), MP4-1080x1920 (9:16), MP4-1080x1080 (1:1)] When the reel is exported Then the output container is MP4 (H.264 video, AAC-LC 48 kHz audio) And resolution, aspect ratio, and letter/pillarboxing respect preset P with no content cropping unless explicitly enabled And the output duration equals the sum of clip durations plus transition durations (±1 frame) And a progress indicator shows percent complete and ETA And the export runs through the existing ClipSpark export pipeline and completes without server errors under typical load; a cancel action stops processing and no asset is saved
Library Persistence, Metadata, Idempotency, and Undo
Given an export completes successfully When the reel is saved to the media library Then the item includes metadata: source video ID, array of clip source start/end timestamps, ruleset snapshot (L,a,b,g,M), selection mode, heatmap layers used, export preset, brand template ID, transition type/duration, creation timestamp, and a downloadable EDL/JSON And invoking "Export" again with identical inputs (same source, selections/rules, template, preset) returns the existing item without creating a duplicate (same asset ID) And invoking "Undo" removes the item from the library and frees associated storage within 30 seconds, with the activity logged And re-exporting after Undo with the same inputs creates a new item with an identical timeline hash

Risk Sentinel

Catch sensitive terms, PII, profanity, or NDA/industry-specific red flags in real time and route them to approvers. Auto-bleep or watermark flagged clips and maintain an audit trail for reviews. Outcome: protect brand and compliance without slowing the show.

Requirements

Real-time Sensitive Term & PII Detection
"As a content producer, I want sensitive terms and PII detected in real time with precise timestamps so that I can address issues before publishing."
Description

Stream-process the speech-to-text output to identify PII (emails, phone numbers, payment numbers, SSNs), profanity, NDA terms, and industry-specific red flags with low latency. Emit precise timestamps and category labels for each hit, with confidence scores and optional regex/entity patterns. Flagged spans are persisted alongside transcripts and are visible in the timeline, captions editor, and highlight selector. Provide event hooks to trigger routing and remediation while maintaining accuracy controls (thresholds, language profiles, false-positive handling).

Acceptance Criteria
Real-Time Detection Latency and Event Emission
Given a live STT token stream for a recording When a sensitive item (PII, profanity, NDA term, or industry red flag) is spoken and the corresponding word is emitted by STT Then a detection event is produced within 300 ms (p95) of the word emission And the event includes startMs and endMs aligned to word boundaries within ±50 ms And the event includes category, subcategory, matchedText, confidence (0.0–1.0), and optional patternId And events are emitted in chronological order with monotonic startMs under 2× real-time stream rate
Persistence and Cross-UI Visibility of Flagged Spans
Given detection events occur in a session When the session transcript is persisted Then each event is saved with fields: id, sessionId, startMs, endMs, category, subcategory, confidence, matchedText, patternId?, createdAt And markers render in the Timeline, Captions Editor, and Highlight Selector at the correct positions And selecting a marker reveals category, confidence, matchedText, and a Go To action And editing transcript text preserves marker time alignment and word span; deleting a marker removes it from storage and all UIs within 1 second
Thresholds, Language Profiles, and False-Positive Handling
Given per-category detection thresholds and language profiles are configured When a threshold is updated Then subsequent detections reflect the new threshold within 5 seconds and below-threshold candidates are suppressed And switching the language profile changes active dictionaries/regexes for new segments immediately And marking a detection as False Positive suppresses re-emission of the same matched pattern and span in the session and records a suppression rule with actor and timestamp And at default thresholds, on the reference evaluation set, PII and profanity precision is >= 0.90 and recall is >= 0.80
Routing Hooks and Automated Remediation (Bleep/Watermark)
Given routing rules are configured for categories When a detection matches a routing rule Then a webhook event is delivered within 200 ms (p95) including idempotency key, retry policy, and payload (ids, timestamps, category, confidence, patternId, matchedText, mediaRefs) And auto-bleep is applied to audio preview for PII/profanity spans with 0 ms pre-roll and 100 ms post-roll within 1 second of detection And a "Sensitive" watermark overlay is applied to flagged video spans in preview within 1 second And an audit log entry is recorded with detectionId, action (bleep/watermark/routed), timestamp, target endpoint, delivery status, and user (if manual)
Admin-Defined Regex/Entity Patterns Support
Given an admin uploads regex/entity patterns via settings When a pattern is enabled Then matching detections include patternId, patternType (regex|entity), matchedText, and capture-group index ranges And the regex engine enforces a 20 ms per-match timeout and input size limits to prevent catastrophic backtracking And Unicode, case-insensitive, and word-boundary options are supported And a Test Pattern endpoint returns matches on provided text using the production engine and flags
Overlap, Chunk-Boundary, and De-duplication Behavior
Given overlapping detections or token chunk boundaries When two detections overlap by >50% and share the same category Then they are merged into a single span with startMs = min(startMs), endMs = max(endMs), and confidence = max(confidence) And partial-word matches at chunk boundaries are expanded to full-word spans using STT word timings And duplicate detections within a 500 ms window for identical text and offsets are discarded And parent-child categories are retained when different (e.g., PII:email inside an NDA phrase)
Custom Policy Builder & Dictionaries
"As a compliance admin, I want to configure custom policies and term lists per workspace so that Risk Sentinel reflects our NDA and industry rules."
Description

Offer an admin UI and API to define reusable policies that combine dictionaries, patterns, categories, thresholds, and remediation defaults. Support workspace- and project-level scoping, rule precedence, versioning, test/simulate mode, import/export of term lists, language-specific variants, and synonyms. Policies can be attached to ingest pipelines so new recordings automatically inherit the correct rules without manual setup.

Acceptance Criteria
Admin UI: Create Reusable Policy With Dictionaries, Patterns, Categories, Thresholds, and Remediation Defaults
Given an authenticated workspace admin in workspace W When they create a policy named "PII Sentinel" combining: dictionary("PII Core v1"), pattern(regex for emails), category(PII), threshold(severity >= 0.7), and remediation defaults(auto-bleep audio, watermark video, route to group "Compliance Approvers") Then the policy is saved with a unique ID, version = 1.0, status = ACTIVE, and scope = NONE And retrieving the policy by ID returns the exact configured components and defaults And the policy appears in the policy catalog and is selectable for pipeline attachment
Policy API: CRUD With Validation and Error Handling
Given a valid API token with admin scope When POST /policies is called with an invalid regex pattern Then the API returns 400 with error.code = "POLICY_PATTERN_INVALID" and a human-readable message When PUT /policies/{id} updates categories, thresholds, and remediation defaults with a valid payload Then the API returns 200 with the updated resource, updatedAt > previous updatedAt, and a new ETag When DELETE /policies/{id} targets a policy not attached to any pipeline Then the API returns 204 and the policy is no longer retrievable When DELETE /policies/{id} targets a policy referenced by pipelines Then the API returns 409 with error.code = "POLICY_IN_USE" and referenceCount > 0
Scoping and Rule Precedence Across Workspace and Project
Given a workspace-level policy A and a project-level policy B that both define remediation for category "PII" And both policies are attached to Project P's ingest pipeline When a recording is processed in Project P Then project-level policy B takes precedence over workspace-level policy A for overlapping rules And the audit log for the job lists appliedPolicies in precedence order [B, A] with reasons And disabling policy B results in subsequent jobs applying policy A without reconfiguring the pipeline
Policy Versioning: Create, Activate, and Roll Back
Given policy "PII Sentinel" at version 1.0 (ACTIVE) When a new draft version 1.1 is created with additional patterns and saved Then version 1.1 has status = DRAFT and version 1.0 remains ACTIVE When version 1.1 is activated Then new jobs started after activation use version 1.1 and the audit trail records version = 1.1 When a rollback to 1.0 is requested Then version 1.0 becomes ACTIVE, 1.1 moves to INACTIVE, and historical jobs continue to reference the version they were processed with
Test/Simulate Mode Execution Without Remediation
Given a policy P and a sample transcript or media file When simulate mode is run for policy P against the sample Then the system returns a simulation report including hit counts by dictionary/pattern, matched spans with timestamps, categories, and confidence scores And the report indicates wouldRemediate = true/false for each hit based on thresholds and defaults And no media is altered, no bleeping/watermarking occurs, and no approval tickets are created And the simulation report is downloadable as JSON and CSV
Import/Export Term Lists With Language Variants and Synonyms
Given an admin has a CSV or JSON file containing terms with language codes (e.g., en, es) and synonym groups When the file is imported into dictionary "Sensitive Terms v2" Then duplicates are de-duplicated case- and accent-insensitively, Unicode is preserved, and an import summary reports importedCount, skippedCount, and errors[] And synonyms are linked to their canonical term and language-specific variants are stored When the dictionary is exported Then the exported file round-trips (re-imports) without data loss and preserves language codes and synonym mappings And if a language variant is missing at runtime, the system falls back to the default language for matching as configured
Pipeline Attachment and Inheritance With Version Pinning
Given workspace W has default policy "Compliance Default" (ACTIVE v1.0) and Project P attaches an additional policy "NDA Red Flags" pinned to v2.3 When a new recording is ingested via Project P's pipeline Then both policies are applied according to precedence rules, and the audit trail lists policy IDs and versions [Compliance Default v1.0, NDA Red Flags v2.3] And removing the project-level attachment takes effect for subsequent ingests without manual restarts And when "NDA Red Flags" v2.4 is activated globally, Project P continues using v2.3 until the pin is changed And jobs started before any attachment change continue processing with the policy set and versions captured at job start
Approval Routing & Publish Gating
"As an approver, I want flagged items routed to me with blocking publish gates so that non-compliant clips never go live."
Description

Create a review queue for flagged items with assignment, escalation, SLAs, and notifications (in-app and email/Slack). Allow single- and multi-step approvals with comments and batch actions. Enforce publish/export gates on clips, captions, and summaries until required approvals are complete or auto-remediation is applied. Surface review status across the editor, highlight generator, and share flows to prevent accidental release of non-compliant content.

Acceptance Criteria
Single-Step Approval with SLA & Escalation
- Given a flagged asset is assigned to a primary approver with an SLA of 4 business hours and a defined escalation group - When the asset enters the review queue - Then the system sets and displays a due-by timestamp on the item - Given the due-by timestamp elapses without approval or rejection - When the SLA is breached - Then the system marks the item as Escalated, reassigns it to the escalation group, and sends in-app, email, and Slack notifications within 60 seconds - Given an approver approves or rejects before the SLA breach - When the action is saved - Then the item is removed from the approver's queue and the audit trail records actor, action, timestamp, and SLA elapsed time - Given a user without approval permission attempts to approve - When the action is submitted - Then the system blocks the action and displays a permission error
Sequential Multi-Step Approval with Required Comments
- Given a policy requiring 2 sequential approval steps (Legal then Comms) - When Legal approves with an optional comment - Then the item advances to Comms and status shows "Step 1/2 Approved" - Given Comms rejects with a required comment - When rejection is saved - Then the item status becomes "Rejected", publish/export remains blocked, and prior approvals remain visible in the audit trail - Given steps are configured as sequential - When Comms attempts to approve before Legal - Then the system prevents the action and displays "Pending prior step" - Given both steps approve - When final approval is recorded - Then publish/export gates lift immediately and status shows "Approved (2/2)"
Batch Actions in Review Queue
- Given a reviewer selects 10 items in the review queue - When they choose "Approve" and confirm - Then all items for which the user has approval permission are approved and removed from the queue - Given one or more selected items are ineligible (e.g., pending prior step) - When the batch action runs - Then the system performs partial success, lists per-item failures with reasons, and leaves failed items selected - Given batch approve completes - When the operation finishes - Then the audit trail records a single batch action with item IDs and individual outcomes - Given batch selection exceeds 100 items - When the reviewer attempts a batch action - Then the system blocks with a message "Batch limit 100" and no actions are taken
Publish/Export Gate Enforcement Across Editor and Share Flows
- Given a clip with outstanding required approvals - When a user attempts to publish, export, or share from the Editor, Highlight Generator, or Share modal - Then the action is blocked, the UI displays the current review status and required steps, and the API returns HTTP 403 with code COMPLIANCE_GATE_BLOCKED - Given all required approvals are complete - When the user attempts to publish/export/share - Then the action succeeds without additional prompts - Given the review status changes (approve/reject) in another session - When the user view is open on any of the three surfaces - Then the status indicator refreshes within 5 seconds
Auto-Remediation Unlocks Gate
- Given a policy that allows auto-bleep or watermark as sufficient remediation for certain flags - When auto-remediation is successfully applied to the asset - Then the system updates status to "Auto-Remediated", lifts publish/export gates for that asset, and records the policy and remediation details in the audit trail - Given auto-remediation fails or is partial - When the system evaluates gate conditions - Then the gate remains enforced and the item stays in the review queue - Given an approver manually overrides after auto-remediation - When approval is recorded - Then the status becomes "Approved" and the audit trail reflects both remediation and human approval
Notifications: In-App, Email, and Slack
- Given a flagged asset is assigned, reassigned, escalated, approved, or rejected - When any of these events occur - Then in-app, email, and Slack notifications are sent within 60 seconds, include asset type, title, step, current status, and a deep link to the review screen - Given a user has disabled email or Slack notifications in preferences - When an event occurs - Then only enabled channels are used; in-app notifications are always delivered - Given a notification delivery failure occurs for a channel - When the system retries - Then it retries up to 3 times over 5 minutes and logs the failure in the audit trail if undelivered
Audit Trail and Status Visibility
- Given any review action (assign, escalate, comment, approve, reject, batch action, auto-remediation) - When the action occurs - Then an immutable audit record is created with actor, role, action, timestamp (UTC), channel (UI/API), prior status, new status, and any comment, and is exportable as CSV - Given an asset under review - When viewed in the Editor, Highlight Generator, or Share flows - Then the same current review status, step count (e.g., 1/2), and gate status are displayed consistently across surfaces - Given a user opens the audit trail - When the user filters by date range, actor, or action type - Then the results update within 1 second for up to 10,000 records
Auto-Remediation (Bleep, Blur, Watermark, Redact)
"As a producer, I want auto-bleeps and redactions applied to flagged segments so that I can safely share content without manual edits."
Description

Provide configurable, non-destructive actions for flagged segments: audio bleep or mute with adjustable duration, transcript/caption redaction or replacement tokens, and optional video watermark overlays for pending or sensitive content. Apply actions on exact timestamped spans, allow preview and rollback, and record the action in the item’s history. Support per-rule default actions and project-level presets to minimize manual edits.

Acceptance Criteria
Auto-Bleep or Mute on Flagged Profanity
Given a flagged profanity segment from 00:01:10.500 to 00:01:12.000 and a project preset with a Bleep/Mute action enabled When auto-remediation runs Then the selected action (bleep tone or mute) is applied exactly from 00:01:10.500 to 00:01:12.000, with configurable pre/post-roll of 0–1000 ms applied as set And the master audio asset remains unmodified (checksum unchanged) And the preview reflects parameter changes within 500 ms And exported media contains the applied remediation while unflagged segments remain unaffected And disabling the action removes the remediation from both preview and export
PII Caption/Transcript Redaction with Replacement Token
Given transcript tokens aligned to audio contain a flagged PII entity and the default action is Redact with token "[REDACTED]" When auto-remediation runs Then only the flagged token(s) are replaced by "[REDACTED]" in transcript, SRT/VTT captions, and on-screen captions And word-level timing and line breaks are preserved within ±40 ms And the original unredacted transcript is retained and can be restored via rollback And search does not return results for the redacted value And exports (SRT, VTT, JSON) include the replacement token and no PII values
Pending/Sensitive Watermark Overlay
Given a clip is in Pending Review and the rule "Apply watermark on pending or sensitive content" is enabled with preset text "SENSITIVE" When previewing or exporting the clip Then a semi-transparent watermark (10–50% opacity as configured) is overlaid per configuration (flagged spans or full clip) at the preset position And the master video asset remains unmodified And the watermark appears in preview and export while status is Pending Review And upon status change to Approved, subsequent previews/exports omit the watermark unless explicitly locked on
Frame/Sample-Accurate Timestamp Application
Given a flagged span with model-provided timestamps start S and end E When a remediation action is applied Then the action's effective start and end differ from S and E by no more than ±20 ms And for variable frame rate media, the frames affected match the expected count derived from timecodes within ±1 frame And overlapping or adjacent flagged spans are remediated exactly to their own boundaries without unintended gaps or overlaps And audio, video, and captions remain synchronized within ±40 ms across the span
Preview and One-Click Rollback of Remediation
Given a user selects one or more remediated segments and activates Preview Remediation When they adjust parameters and then click Rollback Then the selected segments revert to their pre-remediation state without altering original master files And a new history entry is created with actor, timestamp, action, parameters changed, and affected spans And in-session Undo/Redo restores prior/next remediation states And exports generated after rollback reflect the reverted state
Per-Rule Defaults and Project-Level Presets
Given a project-level preset defines per-rule default actions (e.g., Profanity=Bleep with 250 ms pre/post; PII=Redact with token "[REDACTED]") and is set as the project default When a new recording is ingested and flags are detected Then the per-rule defaults are automatically applied within 5 seconds of flag creation And a user can override defaults at the project, clip, or single-span level before export And overrides persist for that entity and do not retroactively change past exports And updating the project preset affects only future ingests while existing overrides remain unchanged
Audit Trail for Remediation Actions
Given any remediation action is created, modified, or rolled back When the change is persisted Then an immutable audit log entry is recorded with event type, UTC timestamp (ms), actor (user/service), rule ID, action type, parameters, affected span(s), and previous/new state references And 100% of remediation events have corresponding audit entries discoverable by filters (date range, rule, clip, actor) And audit entries are retained for at least 365 days and exportable to CSV and JSON And selecting an audit entry opens a timestamped preview of the affected span
Audit Trail & Exportable Compliance Logs
"As a compliance officer, I want a tamper-evident audit log of detections and decisions so that I can demonstrate compliance during reviews."
Description

Capture an immutable history of detections, policy versions, user actions, approvals, and exports with timestamps and actor identities. Generate tamper-evident logs and support retention policies, fine-grained access controls, and exports to CSV/JSON and via API. Provide filtering and reports by category, project, reviewer, and outcome to support audits and internal compliance reviews.

Acceptance Criteria
Immutable Event Logging on Risk Sentinel Actions
Given Risk Sentinel detects sensitive content in a clip When the detection is persisted Then an immutable log entry is created with fields: event_id (UUIDv4), timestamp (ISO 8601 UTC, millisecond precision), org_id, project_id, video_id, clip_id (nullable), category, detected_term/type, policy_id, policy_version, detection_confidence, actor_id (system), actor_type, action_type="detect", previous_hash, hash And event_id is unique across the organization And the log entry is visible via UI and API within 2 seconds of action completion Given a reviewer approves, rejects, overrides, or edits a detection When the action is saved Then a log entry is appended with action_type in {"approve","reject","override","edit"}, actor_id, actor_role, reason (optional), and hash chaining to the previous event in the same stream Given a user exports compliance logs or highlight clips When the export completes Then a log entry is appended with action_type="export", export_id, format (CSV|JSON|API), filter_params snapshot, record_count, and file_checksum (SHA-256)
Tamper-Evidence Verification via Hash Chain
Given the audit trail contains events for a project or org When a verifier recomputes hashes from the genesis event to the latest using stored previous_hash values Then all hashes validate and the daily anchor digest matches the stored value for that day Given any historical event is altered or deleted at the storage layer When the verification runs Then the chain validation fails and surfaces the first invalid event_id and timestamp Given an auditor requests integrity proof for a date range When the system generates the proof package Then it includes: range start/end, anchor digest(s), event_count, Merkle or concatenated-hash digest, and verification instructions, available via download and API
Policy Version Capture and Traceability
Given multiple policy updates occur over time When detections happen before and after a policy update Then each detection log references the exact policy_id and policy_version active at evaluation time and can retrieve the policy snapshot JSON on demand Given a detection is re-reviewed under a newer policy When the outcome is changed Then the new action log references the newer policy_version and retains linkage to the original detection's policy_version Given an auditor filters by policy_version When a report is generated Then counts and records returned correspond only to events tagged with the selected policy_version(s)
Fine-Grained Access Controls for Compliance Logs
Given an Org Admin assigns roles and project/category scopes When a user with role "Compliance Auditor" accesses the Audit Trail Then they can view and export logs across all projects and categories Given a user with role "Reviewer" accesses the Audit Trail When viewing or exporting Then they can only access logs for assigned projects/categories, and PII fields are masked unless the user has the "View PII" scope Given a user lacks the "Export Logs" permission When attempting to export via UI or API Then export controls are disabled and API responds 403 Forbidden Given any user views or exports logs When the action occurs Then an access log entry is created with actor_id, action, resource scope, and timestamp
Retention Policy Enforcement and Legal Holds
Given an Org Admin configures retention rules by category and default project retention (e.g., PII: 365 days; profanity: 90 days) When nightly retention jobs run Then events older than the configured retention are purged and a purge-summary event is recorded with counts by category and purge_job_id Given an event is under legal hold When the retention job runs Then the event is not purged and the hold reason and expiry are visible to auditors Given retention settings are changed When saved Then the new policy applies to subsequent purge runs and prior purge decisions remain auditable via purge-summary events Given purged data is requested via UI or API When queried Then no records are returned and responses indicate "purged due to retention"; only aggregate purge summaries are accessible
Filtering and Reporting for Audit Reviews
Given logs across multiple projects and categories When a user applies filters by category, project, reviewer, outcome, and UTC date range Then the results match the filters and include total_count, page_count, and facet summaries by outcome and category Given a saved report definition exists When it is loaded Then filters, columns, sort order, and date range are restored and the same result set is produced for the fixed time window Given a dataset of up to 250,000 events in scope When executing a filtered query using indexed fields Then the API and UI each return the first page within 3 seconds at p95 and support pagination with a stable sort on timestamp,event_id Given a user opens an event from results When the detail view loads Then all captured fields and the hash/previous_hash linkage context are displayed
Export of Compliance Logs to CSV/JSON and via API
Given a filtered result set When exporting to CSV or JSON via UI Then the file contains all visible fields following the documented schema with headers/keys, uses UTF-8 encoding, timestamps in ISO 8601 UTC, and line count equals the number of exported records Given a large export request up to 1,000,000 events When the export job starts Then it runs asynchronously with progress, supports resumable download, and completes within 30 minutes at p95 or returns a retryable error without partial data corruption Given an API client requests logs via the export endpoint When using pagination parameters (limit<=10,000, cursor) Then the API returns a consistent page, includes next_cursor, respects filters and role-based masking, enforces rate limits, and logs an export action with export_id and checksum Given role-based PII masking applies When exporting via UI or API Then masked fields are redacted consistently and the export metadata notes which fields were masked
Output Safeguards Integration
"As a team owner, I want summaries and highlights to respect flags and approvals so that derivative outputs remain brand-safe."
Description

Ensure Risk Sentinel flags are first-class signals across ClipSpark outputs. Summaries, captions, and one-click highlights default to exclude or mask flagged content until approved. Provide clear UI indicators and override controls with warnings, and propagate approvals/remediations to regenerate safe outputs automatically. Maintain consistency so re-exports and shares always honor the latest review state.

Acceptance Criteria
Default Safeguards Applied to All Outputs
Given a video with segments flagged by Risk Sentinel and no approvals exist When generating a Summary Then all sentences containing flagged content are omitted from the summary text by default Given the same project When generating Captions Then each flagged token range is masked with "••••" in the caption text and the original timecodes are preserved unchanged Given the same project When generating One-Click Highlight Clips Then any highlight overlapping a flagged segment is excluded or auto-bleeped and watermarked per the workspace default policy (exclude or mask) Given any output type When inspecting the generated artifact Then zero unapproved flagged words appear in plaintext, and zero audible unredacted flagged audio is present
UI Indicators and Override with Warning
Given a project with one or more flagged segments When viewing any output preview (summary, captions, highlights) Then a visible "Safeguards active" indicator shows the count of redactions and a link to review details And each redacted region is highlighted on the timeline/transcript with a tooltip stating the flag reason Given the same project When a user clicks "Override safeguards" on an export Then a modal displays the risks, affected segments, and requires explicit acknowledgment (checkbox + typed "OVERRIDE") And proceeding creates an export that includes flagged content only for that export, without changing the review state And the export record is labeled with an "Override used" badge
Role-Based Permissions for Approvals and Overrides
Given user roles of Viewer, Editor, Approver, and Owner When a Viewer or Editor attempts to approve flags or use an override Then the action is blocked with an "Insufficient permission" message and logged Given the same roles When an Approver or Owner approves or remediates a flagged item Then the action succeeds, recording user, timestamp, action (approve/remediate), and reason (required for overrides) And the change appears in the moderation activity log within 5 seconds
Approval Propagation and Auto-Regeneration
Given outputs were previously generated with redactions When an Approver marks one or more flagged items as Approved or Remediated Then only outputs impacted by those items are automatically regenerated to reflect the new review state within 2 minutes And regenerated outputs replace prior versions in the UI with a "Refreshed after review" badge and timestamp And notifications are sent to project watchers indicating which outputs were refreshed And partial approvals restore only the approved segments; unapproved segments remain masked/excluded
Re-exports and Shares Honor Latest Review State
Given an export file or share link was created before a review change When the review state changes (new flags, approvals, or remediations) Then any subsequent re-export or link access reflects the latest review state and never serves unapproved flagged content And stale cached artifacts created before the change are invalidated prior to delivery And the export/download page shows the review-state version (hash/timestamp) used to produce each artifact
Timecode Integrity and Media Treatments
Given caption redactions are applied When playing back the captions Then caption timecodes remain aligned within ±50ms of the source and reading speed limits are not exceeded due to masking Given audio bleeping is enabled for flagged regions When previewing or exporting highlights Then a 1:1 duration beep replaces the redacted audio with no audible original content bleed (leakage < -60 dB) Given watermarking is enabled for flagged regions in video highlights When previewing or exporting Then a visible "Flagged Content" watermark appears only during flagged time ranges at 60% opacity and at least 5% of frame height
Performance & Latency Guarantees
"As a platform engineer, I want clear latency targets and scaling for detection so that live workflows aren’t slowed down."
Description

Define and monitor SLOs for detection and routing latency within live and near-real-time pipelines. Implement backpressure strategies, scalable workers, and streaming inference to meet throughput targets without degrading transcription quality. Expose metrics and alerts for detection lag, queue length, and approval SLA compliance, with fallbacks that switch to asynchronous remediation if real-time thresholds are exceeded.

Acceptance Criteria
99th-Percentile Detection Latency SLO in Live Stream
Given live audio is segmented every 500 ms across 100 concurrent streams When sensitive-term detection runs via streaming inference Then detection latency from segment arrival to decision availability is <= 0.7 s at P95 and <= 1.2 s at P99 over a rolling 10-minute window And no segments are dropped or skipped
Approval Routing Latency and Real-Time Fallback
Given a flag event is emitted for a live stream When routing to an approver is initiated Then the approver UI displays the event within 2 s at P95 and 5 s at P99 And if any single event exceeds 5 s to route, the system auto-applies the configured real-time remediation (bleep/mute/watermark) without pausing the stream And the item is queued for asynchronous review and the approver is notified And the audit log records the fallback reason and timestamps
Backpressure Activation Under Burst Load
Given load increases from 50 to 200 concurrent streams within 60 s When processing queues begin to grow Then backpressure is signaled upstream within 2 s of threshold breach And queue_lag_seconds per stream stabilizes within 30 s to <= 2.0 And no process crashes or data loss occur And if any stream’s queue_lag_seconds remains > 2.0 for 60 s, that stream is switched to asynchronous remediation and an SLA breach is recorded
Auto-Scaling Streaming Inference Workers
Given autoscaling is configured with min 5 and max 50 workers When load rises from 50 to 150 concurrent streams over 2 minutes Then the service scales out within 60 s to maintain detection P95 latency <= 0.7 s and queue_lag_seconds <= 1.0 And when load drops back to 50 streams, it scales in within 5 minutes without dropping in-flight segments or breaching latency SLOs
Transcription and Detection Quality Under Load
Given baseline WER and diarization DER are measured at idle on a representative test set When processing 150 concurrent streams with backpressure and autoscaling active Then WER increases by <= 0.5 absolute and DER by <= 1.0 absolute versus baseline And sensitive-term detection precision and recall each change by <= 2.0 percentage points absolute versus baseline
Metrics Exposure and Alerting for Lag, Queues, and SLA Compliance
Given the service is running in production When the metrics endpoint is scraped Then metrics exist for detection_lag_seconds, routing_lag_seconds, queue_lag_seconds, active_workers, scaling_events_total, approvals_sla_breaches_total with P50/P95/P99 quantiles where applicable And Grafana dashboards display these metrics with at most 1 s resolution And alerts fire within 60 s when detection P95 > 0.7 s for 5 minutes, routing P99 > 5 s for 2 minutes, or queue_lag_seconds > 2.0 for 2 minutes And alerts auto-resolve when metrics return below thresholds for 5 minutes

Speaker Cues

Detect speaker changes, emphasis shifts, and crowd reactions (applause, laughter) to tag likely soundbites as they happen. Filter moments by speaker or cue type to build balanced highlight reels. Benefit: pinpoint crisp, attributable quotes that land with stakeholders.

Requirements

Low-Latency Streaming Inference
"As a live webinar producer, I want speaker cues to appear within 3 seconds so that I can clip and share impactful moments during the session."
Description

Provide real-time cue detection with end-to-end latency under 3 seconds from audio ingress to on-screen tag. Implement streaming ASR and incremental alignment to maintain stable timestamps while allowing late corrections. Use windowed buffering, jitter tolerance, and backfill updates so cues remain accurate as more context arrives. Ensure clock sync between audio, transcript, and timeline, and degrade gracefully on poor networks. Expose latency and confidence telemetry for monitoring and autoscaling. Integrate with ClipSpark’s live session view and write-through to the project timeline for immediate clip creation.

Acceptance Criteria
P95 End-to-End Latency Under 3 Seconds (Live Session)
Given a live audio stream with average network jitter <= 200 ms and packet loss <= 2% When speaker cues (speaker change, emphasis shift, applause, laughter) occur Then the on-screen cue tag appears within 3.0 s at P95 and 3.5 s at P99 from audio ingress timestamp And latency telemetry for the session reports the same P95/P99 within ±50 ms
Timestamp Stability with Incremental Alignment and Late Corrections
Given a cue tag is first emitted with a preliminary timestamp When up to 5 s of additional audio context arrives Then the cue’s timestamp adjustment is <= 150 ms for P95 and <= 300 ms absolute maximum And no more than one timestamp correction event is emitted per cue And the cue identifier remains stable across corrections
Graceful Degradation Under Adverse Network Conditions
Given a live session experiences burst packet loss of 20% for up to 10 s and jitter spikes up to 500 ms When streaming inference continues Then the system enters degraded mode within 2 s, increases buffering, and continues emitting cues And on-screen cue latency remains <= 5.0 s at P95 during impairment and returns to <= 3.0 s at P95 within 10 s after recovery And fewer than 1% of cues are dropped; dropped cues are logged with reason And a user-visible “Degraded network” indicator is shown during impairment
Cross-Component Clock Synchronization
Given synchronized clocks for audio capture, ASR alignment, and UI timeline When cue tags are displayed and written to the timeline Then the time skew between audio, transcript timecodes, and timeline rendering is <= ±50 ms And cue ordering is strictly monotonic with no backward time jumps
Telemetry Exposure for Latency, Confidence, and Buffering
Given any active live session When a client subscribes to the telemetry stream or queries the metrics endpoint Then per-session metrics are published at 1 Hz including: e2e_latency_ms (avg, p95, p99), buffer_depth_ms, clock_skew_ms, asr_word_confidence_mean, cue_confidence_mean, correction_count And metrics include session identifiers and are available within 2 s of session start
Live Session View Integration and Write-Through to Project Timeline
Given a cue is detected in a live session When the cue appears in the live view Then the cue is persisted to the project timeline within 500 ms with its current timestamp and confidence And clicking “Create Clip” creates a clip with 2 s pre-roll and 2 s post-roll around the cue’s final adjusted timestamp And any later timestamp correction updates the timeline record in place within 500 ms
Autoscaling Maintains Latency Under Load Spikes
Given system load ramps from 10 to 150 concurrent live sessions over 5 minutes When autoscaling policies are active Then additional inference capacity is provisioned within 60 s of crossing scale thresholds And P95 end-to-end latency per session remains <= 3.0 s for at least 95% of minutes during the spike And no sessions are dropped during scale-out or scale-in events And capacity scales back down within 10 minutes after load returns to 10 sessions
Multi-Speaker Diarization Engine
"As a podcaster, I want ClipSpark to separate and label speakers so that quotes are clearly attributable in captions and highlight reels."
Description

Detect and segment speaker turns across long-form recordings, robust to overlap, crosstalk, and room acoustics. Output contiguous segments with start/end timestamps, per-segment confidence, and a consistent speaker ID map that persists across the project. Support optional manual labeling (e.g., "Host", "Guest 1") and re-propagation of names through the timeline and captions. Integrate with ASR to align words to speaker segments for fully attributable quotes. Target diarization error rate ≤12% on 2–4 speakers; provide fallback single-speaker mode when confidence is low. Store artifacts for re-indexing and re-export.

Acceptance Criteria
Diarization accuracy ≤12% DER on 2–4 speakers
Given a benchmark set of ≥3 long-form recordings (≥30 min) with 2, 3, and 4 speakers and human-annotated ground truth When the diarization engine processes the set Then the diarization error rate (DER) is ≤ 12% for each recording And the median DER across the set is ≤ 10% And missed speech (Miss) ≤ 5% and false alarm (FA) ≤ 5% of speech duration
Output segment schema and chronological integrity
Given any processed recording When retrieving diarization output via API or file Then every segment includes start_time_ms, end_time_ms, speaker_id, and confidence ∈ [0,1] And segments are strictly ordered with end_time_ms > start_time_ms by ≥ 20 ms And no two segments with the same speaker_id overlap in time And ≥ 95% of speech-active frames (per VAD) are assigned to some speaker segment
Consistent speaker ID mapping across project sessions
Given a project where a single session is processed in multiple passes or reopened When comparing diarization outputs for the same media and model version Then the internal speaker IDs are stable and consistent across runs And a persistent speaker_map (speaker_id -> speaker_key) is stored at the project level And exports from different passes attribute the same voice to the same speaker_id
Manual speaker naming and re-propagation
Given the user renames speaker_id S1 to "Host" in the project When saving the change Then all existing segments with S1 in the project adopt the name "Host" And regenerated captions, transcripts, and exports use "Host" for those segments And subsequent diarization runs in the same project preserve the S1 -> "Host" mapping
Word-level ASR alignment to speaker segments
Given ASR provides word-level timestamps for a recording When aligning words to diarization segments Then each word is attributed to exactly one speaker_id based on its midpoint timestamp And words crossing a speaker boundary are split or attributed with ≤ 50 ms boundary error And exported captions include per-utterance speaker labels and timestamps
Low-confidence detection and fallback single-speaker mode
Given per-segment confidence scores and overlap indicators When the rolling average confidence over any 15-second window falls below 0.35 or conflicting-speaker frames exceed 20% of that window Then the engine emits a fallback_mode = "single_speaker" annotation for that window And downstream outputs and UI/API include a visible "Low confidence—single speaker assumed" flag with timestamps And normal multi-speaker mode resumes automatically when confidence thresholds are restored for ≥ 15 seconds
Persisted artifacts for re-indexing and re-export
Given a completed diarization run for a project When reopening the project or initiating re-index or export Then segment lists, speaker map, ASR-to-speaker alignment, and confidence traces are loaded from stored artifacts without re-running diarization And caches are invalidated and recomputed only when the media content hash or model_version changes And artifacts are available through a documented API endpoint and are included in project backups
Prosody & Emphasis Detection
"As an educator, I want emphasis changes highlighted in the transcript so that I can quickly find the most compelling explanations to share with students."
Description

Analyze prosodic features (pitch, energy, speech rate, pause patterns) to identify emphasis shifts, rhetorical peaks, and moments of heightened delivery. Tag emphasized words/phrases and attach intensity scores and reasons (e.g., "rising pitch + pause"). Align tags at token-level to the transcript and visualize on the timeline with unobtrusive markers. Provide tunable sensitivity to match different speaking styles and languages. Feed emphasis signals into soundbite scoring and search filters.

Acceptance Criteria
Token-Level Emphasis Tagging and Alignment
Given a video with an aligned word-level transcript and audio When Prosody & Emphasis Detection is executed at default settings Then each emphasized token has start/end times within ±50 ms of its transcript timestamps And each emphasized token or phrase includes an intensity score in [0.0,1.0] with two-decimal precision And each emphasis includes 1–3 reason codes from the allowed set {rising_pitch, falling_pitch, energy_increase, energy_drop, rate_accel, rate_decel, boundary_pause} And contiguous emphasized tokens are grouped into phrase spans with an aggregate intensity score (max of member tokens) And no emphasis tag extends beyond media duration or overlaps inconsistently with another tag on the same token And re-running on the same input produces identical emphasized token sets and intensity score deltas < 0.02
Prosodic Peak Detection Accuracy Thresholds
Given a held-out, human-labeled evaluation set (≥60 minutes) across at least 3 languages When detection is run at default sensitivity Then phrase-level emphasis detection achieves F1 ≥ 0.75 overall and ≥ 0.70 per-language And precision ≥ 0.80 and recall ≥ 0.70 overall And false positives on non-emphatic speech average ≤ 2 per minute And median onset timing error of detected phrases relative to labels is ≤ 100 ms
Timeline Visualization of Emphasis Markers
Given a processed video is opened in the editor timeline When the Emphasis layer is toggled on Then emphasis markers render as unobtrusive ticks that do not occlude the scrubber, captions, or speaker labels And hovering a marker shows a tooltip with phrase text, intensity (as %), and reason codes And clicking a marker seeks playback to the marker start within 100 ms And toggling the layer on/off updates the view within 200 ms And rendering 200 markers maintains ≥30 fps during scroll/zoom (avg frame time ≤33 ms) And marker colors and tooltips meet WCAG contrast ≥3:1 And markers are keyboard-focusable and Enter/Space seeks to the marker
Tunable Sensitivity and Persistence
Given the user adjusts the Emphasis Sensitivity control (0–100) in project settings When sensitivity is increased Then the count of emphasis tags is non-decreasing for the same media And when sensitivity is decreased the count is non-increasing for the same media And changes apply to detection results within 5 seconds without requiring re-upload And sensitivity persists per project and language and is restored on reopen And presets (Conservative, Balanced, Expressive) map to specific ranges and selecting a preset updates the control accordingly And a Reset to Default restores factory sensitivity and recomputes tags
Integration with Soundbite Scoring and Search Filters
Given the highlight builder and search panel are open for a processed video When the user enables the filter Emphasis ≥ 0.70 Then only segments containing at least one emphasis tag with intensity ≥0.70 are returned And filtering by reason code (e.g., rising_pitch) returns only segments whose tags include that reason And enabling Emphasis Boost in scoring increases the average rank of segments with intensity ≥0.70 compared to boost off for the same input And toggling filters updates results within 300 ms And exported clips include emphasis tags and intensity/reasons in their metadata
Multilingual and Speaking-Style Robustness
Given videos in at least 5 supported languages with varied speaking styles (fast, slow, monotone, expressive) When detection runs at language-specific default sensitivity Then phrase-level F1 ≥ 0.70 for each language and ≥ 0.75 overall And default sensitivity per language yields a false-positive rate ≤ 2 per minute And the module adds ≤10% to baseline transcription processing time for 60-minute media And if detection confidence for a region is <0.30, no emphasis tag is emitted for that region And the language used for detection follows the transcript language setting and can be overridden per project
Audience Reaction Recognition
"As a conference content manager, I want applause and laughter automatically tagged so that I can surface crowd-validated moments for marketing clips."
Description

Detect and timestamp non-speech reactions such as applause, laughter, and gasps, distinguishing them from background noise, music, or HVAC. Output reaction segments with type, duration, and intensity score; merge adjacent detections and suppress short-lived false alarms. Support mono and multi-channel inputs and maintain robustness in reverberant environments. Integrate reaction tags into the highlight timeline, captions (as [applause], [laughter]), and filters. Aim for ≥90% precision at ≥80% recall on benchmark datasets.

Acceptance Criteria
Streaming Webinar: Real-time Detection and Timestamps
Given a 60-minute mono livestream with annotated applause, laughter, and gasp events When processed in real time Then detection availability latency from event onset is ≤ 2.0 seconds for ≥95% of events And start_ts and end_ts are within ±200 ms of ground truth for ≥95% of detected segments And each detection includes fields: type ∈ {applause, laughter, gasp}, start_ts, end_ts, duration_ms, intensity ∈ [0.0, 1.0] And intensity score monotonically correlates with annotated loudness with Spearman ρ ≥ 0.70
Benchmark Performance: Precision and Recall Targets
Given the agreed Audience Reactions v1 benchmark with class-balanced annotations When the model is evaluated offline Then macro-averaged precision ≥ 90% and recall ≥ 80% overall And per-class precision ≥ 88% and recall ≥ 78% for applause, laughter, and gasp And the 95% bootstrap confidence interval width for overall precision is ≤ 4 percentage points (n ≥ 1000 resamples)
Noise and Music Robustness
Given audio segments containing speech-only, music beds, HVAC noise, and crowd murmur with no annotated reactions When processed Then false positives are ≤ 1 per 30 minutes of audio And ≥ 95% of 10-second negative-only windows contain zero reaction tags And on a 60-minute music-only track, total reaction-tagged duration is 0 seconds (tolerance ≤ 1 segment of < 200 ms)
Reverberant Multi-Channel Robustness
Given 2.0 and 5.1-channel recordings from a reverberant hall (RT60 0.6–1.0 s) with annotated reactions When processed with multi-channel input enabled Then overall precision and recall each degrade by ≤ 5 percentage points versus the same content rendered in anechoic mono And the channel layout is auto-detected and no channel is ignored or causes a processing error And start/end timestamp error remains within ±250 ms for ≥95% of detections
Segmentation: Merge Adjacent and Suppress Blips
Given same-type reaction detections separated by gaps ≤ 300 ms When processed Then the detections are merged into a single segment spanning from the first start_ts to the last end_ts (duration accuracy ±50 ms) And any detected segment with duration < 200 ms is suppressed And adjacent segments of different types remain separate unless temporal overlap ≥ 80%, in which case a single segment is output with the dominant (higher average intensity) type
UI Integration: Captions, Timeline, Filters, Export
Given detected reaction segments in a processed project When the timeline and captions are rendered Then reaction tags appear on the highlight timeline at their timestamps with distinct icons/colors per type And captions include inline tags "[applause]", "[laughter]", "[gasp]" aligned within ±200 ms of segment starts And the Filters panel exposes a Reaction Type facet {applause, laughter, gasp}; selecting any value updates the highlight list within 300 ms And exported SRT/VTT files contain the inline reaction tags with preserved timestamps And the set of segments returned by Reaction Type filtering exactly matches the detection output (1:1 parity)
Soundbite Scoring & Auto-Tagging
"As a knowledge worker, I want the best quotable moments auto-tagged so that I can assemble balanced highlight reels without scrubbing through the whole recording."
Description

Combine speaker attribution, emphasis cues, semantic coherence, and audience reactions to score likely soundbites in rolling windows (e.g., 5–30 seconds). Enforce quotability constraints (complete sentences, named speaker, minimal overtalk) and deduplicate near-duplicates. Expose adjustable scoring weights and length bounds per persona (educator, podcaster, enterprise). Automatically tag top-N moments per speaker to create balanced highlight candidates and feed one-click clip generation with clean in/out points and captions.

Acceptance Criteria
Rolling Window Multi-Signal Soundbite Scoring
Given a long-form video with diarization, ASR, emphasis cues, and audience reaction events available When the system processes audio in rolling windows configurable between 5 and 30 seconds with a 1-second stride Then each window receives a numeric soundbite score composed of weighted sub-scores for speaker attribution, emphasis, semantic coherence, and audience reactions And the score and start/end timestamps are emitted for each window And windows with score >= the active persona threshold (default 0.70) enter the candidate set And processing latency from end of window to score availability is <= 3 seconds
Enforce Quotability Constraints for Candidate Soundbites
Given a candidate window in the set When enforcing quotability constraints Then the in/out points align to sentence boundaries from ASR punctuation with <= 200 ms tolerance at each edge And the dominant speaker is identified and named with confidence >= 0.80 And overlapped speech proportion within the window is <= 10% And the final window duration falls within the active persona min/max bounds
Near-Duplicate Detection and Suppression
Given the set of candidate windows for a video When computing transcript-embedding similarity across candidates Then any pair with cosine similarity >= 0.90 and temporal overlap >= 30% is clustered And only the highest-scoring member of each cluster is retained; the rest are suppressed And the resulting tagged set contains no two items with transcript similarity >= 0.90 within any 120-second span And a deduplication log lists suppressed candidate IDs with their retained representative ID
Persona-Based Weights and Length Bounds Configuration
Given persona templates Educator, Podcaster, and Enterprise When a user selects a persona Then default weights for speaker attribution, emphasis, semantic coherence, audience reactions, and default min/max clip length are applied When the user adjusts any weight (range 0.0–1.0) or min/max length (range 5–60 s) and saves Then the new configuration persists at the workspace level and is used for subsequent scoring runs And an API endpoint returns the effective configuration (persona, weights, min/max, threshold, version) for any video
Balanced Auto-Tagging of Top-N Moments per Speaker
Given a specified N (default 3) for auto-tagging When auto-tagging is executed for a video Then up to N highest-scoring non-duplicate candidates are tagged per speaker And the total tagged moments equals the sum over speakers of min(N, available candidates) And if a speaker has zero candidates, no placeholder tags are created And each tag includes speaker name, score, start/end timestamps, and primary contributing signals
One-Click Clip Generation with Clean In/Out and Captions
Given any tagged moment When the user triggers one-click clip generation Then the exported clip uses the tagged start/end with edge padding <= 250 ms and aligns to word boundaries And captions for the clip are generated with average word alignment error <= 200 ms and contain no missing words relative to the tagged transcript And the exported assets include MP4 video and a VTT or SRT sidecar within <= 2x the clip duration processing time And the clip audio contains no overtalk above -30 dBFS relative to the dominant speaker during the clip
Cue-based Filter & Query UI
"As a video editor, I want to filter moments by speaker and cue type so that I can quickly assemble a balanced set of highlights."
Description

Provide timeline and list views that filter moments by speaker, cue type (emphasis, applause, laughter), intensity, duration, and confidence. Include text search for speaker names and quoted phrases, quick previews with waveform and captions, and keyboard shortcuts for triage (accept, reject, add to reel). Support saved filters and shareable views across the team. Ensure accessibility (WCAG AA) and responsive performance on 2-hour+ recordings with thousands of tags.

Acceptance Criteria
Filter Moments by Speaker, Cue Type, Intensity, Duration, and Confidence (Timeline View)
Given a 2h10m recording with at least 3,000 cue tags across three or more speakers and cue types (emphasis, applause, laughter) When the user sets Speaker = "Alice", Cue Type in {emphasis, laughter}, Intensity ≥ 0.7, Duration between 1.0 and 8.0 seconds, and Confidence ≥ 0.85 Then the timeline view displays only moments whose tags simultaneously satisfy all active filters And the list view items and total count match the timeline selection exactly And an empty-state appears if zero moments match, with a clear option to reset filters And filter chips show all active constraints and can be individually cleared And removing any single filter reintroduces previously excluded moments appropriately And filter changes update visible results and counts within 800 ms of user action And all active filters persist across page reloads and back/forward navigation
Text Search for Speaker Names and Quoted Phrases
Given an indexed recording with speaker labels and time-aligned captions When the user searches for an exact phrase using quotes, e.g., "renewable energy" Then only moments whose captions contain that exact phrase (case-insensitive, word order preserved) are returned And matching terms are highlighted in result excerpts and the preview captions When the user searches for a speaker name, e.g., Alice Then moments attributed to that speaker are returned regardless of cue type And search terms can be combined with active filters using AND logic to narrow results And the first page of results renders within 500 ms for up to 3,000 tags And clearing the search box restores the prior filtered set without residual highlighting
Quick Preview with Waveform and Captions
Given a filtered result set in list or timeline view When the user activates a moment (click, Enter, or Space) Then a preview opens inline without navigating away from the current page And the waveform centers the moment with ±5 seconds context and a visible playhead And captions are displayed and stay in sync with audio, highlighting the active word And playback controls include play/pause, scrub, loop-on-moment, and speed from 0.5× to 2.0× And the preview becomes interactive within 300 ms if media is cached and within 800 ms if uncached And closing the preview returns keyboard focus to the triggering control
Keyboard Triage: Accept, Reject, Add to Reel
Given focus is on a moment row or its open preview When the user presses A Then the moment is marked Accepted, visually indicated, and added to the current reel When the user presses R Then the moment is marked Rejected, visually indicated, and removed from the current reel if present When the user presses E Then the moment is added to the current reel without altering its accept/reject state And ARIA live announcements communicate each triage action to assistive technologies And triage states persist across view switches and page reloads And shortcuts function in both timeline and list views without conflicting with default browser behaviors
Saved Filters and Shareable Views
Given an active combination of filters, search terms, sort order, and view mode (timeline or list) When the user saves the view with a name Then the saved view appears in the user's list with its name and is selectable And reselecting the saved view restores all previously saved filters, search, sort, and view mode exactly And using Copy Link generates a URL that restores the same state for teammates with access And saved views persist across sessions and devices for the same account And renaming or deleting a saved view updates for all team members within 5 seconds And opening a share link without access prompts for authorization and does not reveal underlying data
Performance and Responsiveness on 2-Hour+ Recordings
Given a 2h30m recording containing at least 5,000 cue tags across six speakers When the user loads the Cue-based Filter & Query UI Then the UI becomes interactive within 2 seconds on a modern laptop and within 3 seconds on a mid-range mobile device When the user applies any single filter or text search Then results update and render within 800 ms at the 95th percentile and within 1,200 ms at the 99th percentile And list view scrolling maintains 60 fps at median and not less than 30 fps at the 99th percentile via virtualization And timeline zoom and pan respond within 100 ms of input And in-browser memory usage remains under 500 MB during active use And no unresponsive script warnings occur during a continuous 10-minute session
Accessibility Compliance (WCAG 2.2 AA)
Given a keyboard-only user When navigating filters, search, timeline, list, preview, and triage controls Then all controls are reachable via Tab/Shift+Tab in logical order with visible focus indicators And all actions (filtering, searching, preview playback, triage) are operable via keyboard controls only And ARIA roles, names, and states are present for interactive elements; triage state changes are announced via aria-live And text contrast is at least 4.5:1 and non-text contrast is at least 3:1 And screen reader users can access speaker, cue type, intensity, duration, and confidence for each result And automated audits (axe-core/Lighthouse) report zero critical accessibility violations on the page
Tagged Exports & NLE Integration
"As a social media producer, I want to export cue-tagged clips directly into my editing workflow so that I can finish edits without rebuilding timelines."
Description

Export cue-tagged clips and timelines as SRT/VTT (with cue annotations), EDL/AAF/FCXML for NLEs (Premiere, Final Cut, DaVinci), and JSON via API. Preserve source timecodes, speaker labels, and cue metadata in sidecars. Provide one-click export presets (social vertical, podcast teaser) and webhook callbacks when render jobs complete. Validate exports against sample projects and document the schema for third-party integrations.

Acceptance Criteria
Export SRT/VTT with Cue Annotations
Given a processed project with detected speaker labels and cue tags (emphasis, applause, laughter) And the user selects Captions export with "Include cue annotations" enabled When SRT and VTT files are exported Then each cue’s start and end timecode matches the source timebase within ±1 frame (including drop/non‑drop handling) And each cue carries speaker label and cue type annotations per the published ClipSpark SRT/VTT Annotation Schema v1.0 And a schema validator reports 0 errors for both files And re‑importing the VTT into ClipSpark reproduces the same number of cues with identical timecodes and annotations
EDL/AAF/FCXML Interoperability with NLEs
Given a highlight timeline built from Speaker Cues with filters applied (by speaker and cue type) When the user exports EDL (CMX3600), AAF, and Final Cut XML Then each exported format contains the same number of clips as the ClipSpark timeline And each clip’s in/out timecodes match the source within ±1 frame And speaker label and cue type are preserved as clip markers/notes per format capability And the files import without errors into the NLE versions pinned in the CI compatibility matrix (Premiere Pro, DaVinci Resolve, Final Cut Pro) And after import, clip ordering and total duration match the ClipSpark timeline exactly
JSON API Export and Webhook Completion Callbacks
Given a valid API token and a processed project id When the client POSTs to /v1/exports with a preset id and a webhook URL Then the API responds 202 Accepted with a job_id and initial status queued When the job completes Then ClipSpark POSTs to the webhook URL with an HMAC‑SHA256 signature header and payload including job_id, status=completed|failed, preset id, and download URLs for all generated artifacts (SRT, VTT, EDL, AAF, FCXML, JSON) And the JSON export conforms to the published JSON Schema v1.0 including fields: timebase, segments[], cues[type, start, end, speaker, confidence], and source_media metadata And on webhook delivery failure, ClipSpark retries at least 3 times with exponential backoff
One‑Click Export Presets (Social Vertical, Podcast Teaser)
Given a project with at least three selected highlight clips When the user clicks the Social Vertical preset Then ClipSpark renders a 1080x1920 package, limits any single exported reel to 60 seconds (unless user overrides), and generates sidecars (SRT, VTT with annotations, EDL/AAF/FCXML, JSON) And the exported assets include preserved source timecodes and speaker/cue metadata in sidecars When the user clicks the Podcast Teaser preset Then ClipSpark renders a 1920x1080 package with identical sidecars and preserved metadata And a webhook is sent on completion containing the preset id and artifact URLs
Timecode Preservation and Sidecar Integrity
Given source media with known starting timecode and frame rate (including drop‑frame or non‑drop) When any supported export is generated Then all sidecars declare and use the source timebase and starting timecode And random sampling of 20 exported cues across the timeline shows no drift beyond ±1 frame at 30, 45, and 60 minutes And for variable‑frame‑rate sources, exported timecodes are normalized to a declared constant timebase with accuracy within ±2 frames across the full duration And each sidecar embeds schema_version and generator metadata
Exports Respect Filters and Segment Bounds
Given the user filters by speakers (e.g., Alice, Bob), cue types (e.g., emphasis, applause), sets a confidence threshold ≥0.80, and merges adjacent cues within 1.5 seconds When the user exports in any format Then only segments that satisfy the filters are included in all artifacts And segment in/out points in exports match the filtered timeline bounds within ±1 frame And cue‑type and speaker annotations are preserved in markers/notes and JSON And the JSON export records the filter parameters used
Schema Documentation and Sample Project Validation
Given versioned public documentation for SRT/VTT annotations, JSON schema, and NLE export mappings When running the automated validation suite against maintained sample projects for each NLE Then all exporters produce artifacts that pass schema validation and import successfully into the NLEs defined in the compatibility matrix And the docs include end‑to‑end examples and code samples that build and run without errors And any backward‑incompatible schema change triggers a failing CI check until migration notes and version bump are published

Goal Picker

Tell ClipSpark what you’re trying to make—Promo, Recap, Quote Reel, or Study Aid—and Fastlane auto-tunes clip length, tone, caption style, and crop for that outcome. Result: relevant first clips with zero guesswork and no settings maze.

Requirements

Goal Selection UI
"As a busy creator, I want to pick my goal in one click so that ClipSpark auto-configures outputs without me navigating complex settings."
Description

Provide a prominent, accessible picker to choose a production goal (Promo, Recap, Quote Reel, Study Aid) in one click. The UI presents clear labels, iconography, and short tooltips that describe how each goal affects clip length, tone, captions, and crop. It remembers the last used goal per user/workspace, supports keyboard and screen-reader navigation, and exposes a configuration source so product can add or deprecate goals without code changes. Selecting a goal triggers downstream orchestration without exposing a complex settings panel, aligning with Fastlane’s zero-guesswork promise.

Acceptance Criteria
One-Click Goal Selection Triggers Orchestration
Given the user is on the Fastlane page with a loaded recording and no goal selected, When the user clicks a goal card (Promo, Recap, Quote Reel, Study Aid) once, Then the goal becomes active with a visible state change within 100 ms and no settings panel opens, and the orchestration request is enqueued within 500 ms carrying that goal’s parameters. Given a goal is already active, When the user selects a different goal, Then only the newly selected goal remains active, a new orchestration request is sent with the new goal’s parameters, and any pending request for the previous goal is canceled. Given a goal selection occurs, When analytics are processed, Then an event GoalSelected is logged with properties {goal, userId, workspaceId, sessionId, timestamp} and a ≥95% delivery success rate per session. Given the orchestration payload is inspected, Then it includes defaults for {clipLength, tone, captionStyle, crop} that match the configuration entry for the selected goal (exact key equality). Given rapid double-clicks or repeated taps within 300 ms, When deduplication is applied, Then only one orchestration request is emitted per unique selection change.
Prominent and Discoverable Goal Picker Placement
Given a desktop viewport width ≥ 1024 px, When the Fastlane page loads, Then the goal picker is visible without scrolling in the initial viewport and each goal card has a minimum interactive area of 44x44 px. Given a mobile viewport width ≤ 480 px, When the Fastlane page loads, Then the goal picker appears within the first screenful (≤ 600 px vertical offset) and the options are arranged without horizontal scrolling (single row carousel is not used). Given the picker is rendered, Then label text contrast against background is ≥ 4.5:1 and icon contrast is ≥ 3:1. Given page interactive (DOMContentLoaded) fires on a 20 Mbps connection, When assets are loaded, Then the goal picker renders within 1000 ms at p50 and within 2000 ms at p95.
Clear Labels, Icons, and Tooltips Communicate Effects
Given the goal cards are displayed, Then the visible labels are exactly: "Promo", "Recap", "Quote Reel", and "Study Aid", and each card displays an icon without load errors. Given a user hovers or focuses a goal card, When the tooltip is triggered, Then the tooltip appears within 150 ms and contains a sentence that mentions clip length, tone, captions, and crop (all four terms present). Given a tooltip is visible, When the user blurs the card or presses Escape, Then the tooltip is dismissed within 100 ms and does not cover more than 40% of the goal card area while shown. Given the tooltip exists, Then the card’s control has aria-describedby referencing the tooltip content, and the tooltip text length is between 60 and 200 characters.
Remembers Last Used Goal per User/Workspace
Given a user selects a goal in Workspace A, When the session ends and the user returns later, Then the same goal is preselected for Workspace A before any manual interaction. Given a user switches from Workspace A to Workspace B, When the picker loads, Then the preselected goal reflects Workspace B’s last selection, independent of Workspace A. Given network persistence fails, When selection occurs, Then the choice is cached locally and synchronized to the server within 10 seconds of connectivity restoration. Given a goal is preselected from history, When the user explicitly chooses a different goal, Then the new choice immediately overrides the stored value.
Keyboard Navigation and Selection Compliance
Given keyboard-only navigation, When focus enters the goal picker, Then focus lands on the selected goal (or the first goal if none selected) with a visible focus indicator of ≥ 2 px contrast outline. Given focus is within the picker, When ArrowLeft/ArrowRight (or ArrowUp/ArrowDown) are pressed, Then focus moves between goals without leaving the picker; Home/End move to first/last; Tab moves out of the picker. Given a goal has focus, When Space or Enter is pressed, Then that goal becomes selected and triggers orchestration exactly once. Given navigation is cyclical, When focus moves past the last/first goal with Arrow keys, Then it wraps to the first/last goal and no tab trap occurs.
Screen Reader Announcements and Focus Management
Given assistive technology is enabled (NVDA + Chrome or VoiceOver + Safari), When focus lands on the picker, Then it is announced as a radiogroup named "Production goal" with the correct count of options. Given a goal receives focus, Then the screen reader announces name, role, position (e.g., "Promo, radio button, 1 of 4"), and selection state. Given a goal is selected, When the selection changes, Then the change is announced without duplicate announcements and no live region spamming occurs (max one polite announcement per change). Given help text is needed, When the user focuses a goal, Then the tooltip content is programmatically associated and read on demand via aria-describedby or aria-details without requiring a mouse hover.
Config-Driven Goal Catalog (Add/Deprecate Without Code)
Given the app starts, When the picker initializes, Then goal definitions are loaded from a configuration source conforming to schema {id, label, iconPath, defaults:{clipLength,tone,captionStyle,crop}, order, deprecated?, replacedBy?} and validated; invalid entries are rejected with a logged error. Given a valid new goal is added to the configuration, When the app reloads, Then the new goal appears in the picker in the configured order without a code deployment. Given a goal is marked deprecated in the configuration, When the picker loads, Then the deprecated goal is hidden from new selection but previously stored selections map to the configured replacedBy goal; if no mapping, the deprecated goal renders with a "Deprecated" badge and a prompt to choose another. Given the configuration fails to load, When the picker initializes, Then a local default configuration is used and the UI remains functional, with a retry attempted in the background within 30 seconds. Given configuration defaults are updated, When a goal is selected, Then the orchestration payload uses the latest defaults from configuration without requiring a client release.
Goal-to-Parameter Engine
"As a product-minded editor, I want goals to translate into predictable settings so that outputs are consistent and easy to refine over time."
Description

Implement a deterministic mapping layer that converts the selected goal into a versioned parameter bundle consumed by the analysis and generation pipeline. Parameters include: target clip length ranges and count, tone directives for summarization and captions, caption style preset, crop aspect ratio preferences, highlight ranking weights (e.g., speaker energy, keyword density, novelty, visual salience), and export specs. The engine validates parameter schemas, supports feature flags per goal, logs which bundle version produced outputs, and allows safe overrides. This enables consistent, explainable results and rapid iteration on goal behavior without refactoring core pipelines.

Acceptance Criteria
Deterministic Goal-to-Bundle Mapping
Given a selected goal in {Promo, Recap, Quote Reel, Study Aid} and no overrides When the engine generates the parameter bundle Then the bundle includes all required sections: target_clip_length_range, target_clip_count, tone_directives, caption_style_preset, crop_aspect_ratio_preferences, highlight_ranking_weights, export_specs And the bundle has a semantic version id matching ^g2p-v\d+\.\d+\.\d+$ And the same input (goal, app_version, feature_flag_snapshot) produces a byte-identical bundle (checksum unchanged) across 3 consecutive calls And the mapping completes within 50 ms at p95 under nominal load (≥100 RPS) And different goals produce distinct bundles (checksum differs)
Schema Validation and Error Handling
Given an overrides payload that is missing a required field or contains a type mismatch When the engine validates the payload Then it rejects the request with HTTP 422 and error_code=PARAM_SCHEMA_INVALID, returning the JSON pointer path to the first invalid field and a human-readable message And a validation_failure event is logged with goal, bundle_version, and error_code Given an unsupported goal string When the engine maps the goal to parameters Then it returns HTTP 400 with error_code=GOAL_UNSUPPORTED and the list of supported goals
Bundle Versioning and Audit Logging
Given any successful bundle creation When downstream outputs are generated using this bundle Then the engine writes an immutable audit record containing: goal, bundle_version, bundle_checksum, feature_flag_snapshot_id, overrides_checksum, timestamp, and request_id And the audit record is retrievable by request_id via the internal API within 60 seconds of creation And changing any parameter in the bundle increments the semantic version according to policy (backward-compatible=minor, breaking=major) And the audit record passes integrity verification (checksums validate)
Feature Flags per Goal with Fallback
Given a goal with feature flags defined (e.g., use_novelty_weight_v2=true) When the engine generates the bundle Then the bundle reflects the current flag values and includes the captured flag_snapshot_id And toggling a flag changes only the flagged parameters while keeping unrelated parameters identical (checksum differs only for affected section) And if the flag service is unavailable, the engine uses the last-known-good snapshot not older than 24 hours and marks source=fallback; if none exists, it uses default flags and emits flag_fallback_used And determinism for a run is scoped to the captured flag snapshot
Safe Overrides with Precedence and Guardrails
Given allowed override keys {target_clip_length_range, target_clip_count, crop_aspect_ratio_preferences, export_specs.bitrate} When a user supplies overrides within allowed bounds Then the engine applies overrides with higher precedence than goal defaults and feature flags and revalidates the final bundle schema And attempts to modify locked keys {caption_style_preset, tone_directives, highlight_ranking_weights} are rejected with HTTP 403 and error_code=OVERRIDE_NOT_ALLOWED, listing offending paths And out-of-bounds overrides are rejected with HTTP 422 and error_code=OVERRIDE_OUT_OF_BOUNDS, including min/max details per field (no partial application) And applied overrides are recorded in the audit log as a diff from goal defaults
Highlight Ranking Weights Normalization and Effect
Given any generated bundle When highlight_ranking_weights are produced Then weights include keys {speaker_energy, keyword_density, novelty, visual_salience} (plus optional others), are non-negative, and normalize to 1.0 ± 0.01 And goal-specific bounds are enforced (e.g., Study Aid requires keyword_density ≥ 0.35) And if a signal is unavailable, its weight is redistributed proportionally among available signals and a signal_missing event is logged And increasing speaker_energy weight by ≥0.2 (with renormalization) on a fixed test corpus changes the top-5 highlights (Jaccard index < 1.0) in at least 70% of videos
Pipeline Consumption and Export Spec Propagation
Given a sample video and goal=Quote Reel with default flags and no overrides When the pipeline consumes the produced bundle Then generated clips conform to target_clip_length_range, target_clip_count, caption_style_preset, crop_aspect_ratio_preferences, and export_specs (codec, container, bitrate) And ≥95% of produced clips are within the specified length range; any outliers are logged with reason And user-facing metadata for each output includes bundle_version and bundle_checksum And end-to-end tests pass for at least two goals (e.g., Promo and Study Aid) without manual intervention
Instant Preview & Apply
"As an educator, I want to see goal-specific clip previews immediately so that I can confirm direction before committing to full processing."
Description

Upon goal selection, generate and display fast previews of top candidate clips (thumbnails or short playable snippets) with estimated durations, captions, and crops applied. Provide a single "Apply Goal" action that commits the chosen goal and queues full-resolution generation. Handle states gracefully (e.g., source still analyzing) with progress indicators and optimistic UI. Enforce performance budgets for preview generation, offer cancellation, and cache previews per goal to avoid recomputation when users switch goals. This reduces guesswork and accelerates time-to-first-clip.

Acceptance Criteria
Goal Selection Triggers Fast Previews
Given a processed or processing video is available and the user is on the Goal Picker view When the user selects one of Promo, Recap, Quote Reel, or Study Aid Then the system generates at least 3 candidate clip previews and displays them as thumbnails or 2–5 second playable snippets And each preview shows an estimated duration (in seconds), auto-applied captions, and the selected crop And the first preview appears within 2 seconds at P90 and 4 seconds at P99 And all previews for the selected goal finish loading within 6 seconds at P90
Graceful State While Source Analysis Is In Progress
Given the source video analysis is still in progress When a goal is selected Then the preview area renders placeholder skeleton cards immediately (<200 ms) And a progress indicator shows current analysis stage or percent and updates at least every 1 second And "Apply Goal" remains disabled until at least one preview is playable And when analysis completes, placeholders hydrate into previews in place with layout shift < 50 px
Preview Performance Budget and Cancellation
Given previews are generating for the currently selected goal When the user clicks "Cancel previews" Then all in-flight preview requests are aborted within 500 ms And no additional preview requests are issued after cancellation And the UI returns to the pre-goal-selection state within 300 ms And telemetry records a cancel event with goal type and elapsed time And time to first preview for non-canceled sessions is ≤ 2 seconds at P90 and ≤ 3.5 seconds at P95
Apply Goal Queues Full-Resolution Generation
Given at least one preview is displayed for the selected goal When the user clicks the single "Apply Goal" action Then the selected goal is committed to the project context And full-resolution generation jobs are queued for all currently displayed candidate clips And each job includes the goal parameters (clip length, tone, caption style, crop) used in the preview And a confirmation toast appears within 500 ms and a queue/progress indicator becomes visible And the user can navigate away without canceling the queued jobs
Per-Goal Preview Caching and Reuse
Given the user has previously generated previews for a goal on the same source video in the current session When the user switches to a different goal and then back to the original goal Then cached previews are re-shown within 300 ms And no network call is made to the preview-generation endpoint for cache hits And cached previews are invalidated only when the source video version or goal configuration changes
Preview Error Handling and Retry
Given a preview generation request fails or times out When the user has selected a goal Then the affected preview card shows an inline error state with a "Retry" control And other previews continue to load and remain interactable And a timeout is triggered at 8 seconds per preview with up to 2 automatic retries using exponential backoff And if all previews fail, a non-blocking banner explains the issue and "Apply Goal" is disabled
Preview-to-Final Fidelity
Given previews are displayed for a selected goal When full-resolution generation completes for the same clips Then the final clip durations differ from the preview estimated durations by no more than ±15% And caption content in previews matches the full-resolution captions with ≥ 95% word-level agreement And applied crop framing in previews matches full-resolution within a 5% bounding box variance
Overrides & Custom Presets
"As a podcaster, I want to fine-tune the auto settings and save them as my default so that future projects match my style with minimal effort."
Description

Allow users to tweak auto-tuned parameters (e.g., length range, caption intensity, crop preference) after selecting a goal, then save those tweaks as named presets scoped to that goal. Support set-as-default per user/workspace, reset-to-default, and visibility controls (private vs shared). Enforce safe bounds to protect downstream quality and rendering SLAs. Persist preset versions and reconcile gracefully when the underlying goal schema changes. This provides flexibility without reintroducing a settings maze.

Acceptance Criteria
Override Parameters After Goal Selection
Given a user has selected a Goal (Promo, Recap, Quote Reel, or Study Aid) When the user opens Overrides from the goal confirmation screen Then the Overrides panel opens within 1 click and within the same view (no page navigation) And the panel shows only parameters applicable to the selected Goal with their current auto-tuned defaults prefilled And all controls are accessible within a single scrollable panel with no more than one level of grouping (no nested dialogs) And changes to any parameter update the preview within 500 ms on a typical broadband connection And the user can Apply overrides to the current generation without saving a preset And an Unsaved Changes indicator appears until the user applies or saves a preset
Save Named Preset Scoped to Goal
Given a user has modified parameters for a selected Goal When the user selects Save as Preset and enters a name Then the system validates the name is non-empty, <= 50 characters, and unique within the combination of (Goal, Visibility scope) And the preset is saved scoped to that Goal only and includes all current parameter values And save completes within 1 second P95 And the new preset appears in the preset picker for that Goal without page refresh And the user receives confirmation feedback (toast) and the Unsaved Changes indicator clears
Set User and Workspace Defaults
Given at least one preset exists for a Goal When a user marks a preset as My Default Then that preset auto-applies whenever that user selects that Goal And the user can Clear My Default to revert to the Goal baseline When a workspace admin marks a preset as Workspace Default for a Goal Then that preset auto-applies for all workspace members who do not have a personal default for that Goal And personal default takes precedence over workspace default for that user And all default set/clear actions are recorded with actor, timestamp, goal, and preset id in the audit log
Reset to Goal Defaults
Given a user has applied a preset or modified overrides for a Goal When the user clicks Reset to Goal Defaults Then all parameters revert to the Goal’s baseline schema defaults And any selected preset is deselected and the state is labeled Baseline And if there are unsaved changes, the user is prompted to confirm before resetting And the reset action completes within 500 ms P95 and clears the Unsaved Changes indicator
Visibility Controls and Permissions
Given a user is saving a preset When the user selects visibility = Private Then the preset is only visible and editable by that user When the user selects visibility = Shared (Workspace) Then only users with role Editor or Admin can create or update shared presets; otherwise the option is disabled And shared presets are visible to all workspace members and usable by all, but editable/deletable only by owners and workspace admins And any user can Clone a shared preset to a private preset And visibility is displayed in the preset list and filterable by users
Safe Bounds Enforcement and SLA Protection
Given the Goal schema defines allowed ranges and options for each parameter When a user enters a value outside the allowed bounds (e.g., clip length outside schema min/max) Then the UI prevents the entry from being applied or saved, displays the allowed range, and highlights the invalid control And the server re-validates on save/apply and rejects out-of-bounds values with a structured error (HTTP 400, code=INVALID_PARAMETER) within 200 ms P95 And presets that pass validation do not cause rendering SLA regressions: preset application API P95 latency <= 200 ms; client-side apply P95 <= 100 ms; no increase in render job error rate > 1% absolute vs baseline over a 24h window
Preset Versioning and Goal Schema Reconciliation
Given a preset exists for Goal schema version Vn When the Goal schema updates to Vn+1 (parameters added, removed, or renamed) Then existing presets are auto-migrated on first use or in background: added parameters adopt the new schema defaults; removed parameters are dropped; renamed parameters are mapped via a server-provided migration map And a new preset version is created (original preserved as read-only), with version metadata (from_version, to_version, migration_time, actor=system) And if migration cannot be completed deterministically, the preset is marked Incompatible, hidden from default application, and the user is notified with remediation steps; no render attempts proceed with incompatible presets And users can view version history and roll back or re-save a migrated preset And all migrations are recorded in the audit log
Goal-Specific Caption Styles
"As a content marketer, I want captions to match the intent of a promo versus a recap so that the clips feel on-brand and effective without manual restyling."
Description

Create a caption styling library mapped to goals: Quote Reel emphasizes speaker name and quoted lines; Study Aid highlights terminology and timestamps; Promo supports optional CTAs/emphasis; Recap favors clean, unobtrusive captions. Integrate with brand kits (fonts, colors, logo placement), ensure readability across aspect ratios, and support accessibility (contrast, size, caption safe areas). Provide per-goal punctuation, emoji usage, and emphasis rules that the NLG captioner adheres to. This ensures captions reinforce the intended outcome without manual editing.

Acceptance Criteria
Apply Goal-Specific Style on Selection
Given a user selects a goal (Promo, Recap, Quote Reel, Study Aid) in Goal Picker and generates the first clip When captions are rendered for that clip Then the applied caption style tokens (font family, size, weight, color, alignment, background/box, stroke/shadow, position) match the selected goal's style profile exactly And the goal id and style profile version are persisted in the clip metadata And the computed render styles equal the resolved style tokens (0 differences)
Brand Kit Overrides Per Goal
Given a workspace brand kit defines fonts, primary/secondary colors, and logo placement When a user selects any goal and renders captions Then goal styles are overridden by brand kit properties where defined and fall back to goal defaults where not defined And logo placement does not overlap captions and remains within safe area And the resolved style token snapshot is stored with the clip And updating the brand kit does not retroactively change existing published renders; new renders use the updated tokens
Accessibility—Contrast, Size, and Safe Areas Across Ratios
Given 9:16, 1:1, and 16:9 aspect ratios with default crops When captions are rendered for each ratio Then text contrast against its immediate background is >= 4.5:1 (or >= 3:1 if text height >= 4% of frame height) And minimum text height is >= 3.5% of frame height or 42 px on 1080p, whichever is greater And captions remain inside caption-safe area with at least 5% margin from all edges and do not overlap logos And a maximum of 2 lines per segment, maximum 42 characters per line, and reading speed <= 17 characters per second And no caption text is clipped or occluded in any tested ratio
Goal-Specific NLG Style Rules Enforcement
Given per-goal punctuation, emoji, and emphasis rules are configured When the NLG captioner generates captions for each goal Then Promo: up to 2 emojis per segment; CTA line only if CTA is enabled; emphasis allowed on callouts And Recap: 0 emojis; sentence-case; minimal emphasis only And Quote Reel: wrap spoken quote in quotation marks; 0 emojis; preserve smart punctuation; emphasis on key phrase allowed And Study Aid: 0 emojis; emphasize terminology using defined style; include [mm:ss] timestamp per segment And any rule violation is flagged and the segment is regenerated or marked for manual review
Promo CTA Optionality and Formatting
Given the Promo goal is selected and the CTA toggle is present When the user enables a CTA with text up to 60 characters and an optional URL Then a CTA line is appended with distinct styling that passes WCAG AA contrast and stays within safe area And disabling the CTA removes it from preview and export renders And URLs longer than 30 characters are ellipsized preserving the domain (e.g., example.com/…) And the CTA line height does not exceed 1.5x a regular caption line and never overlaps caption text
Study Aid Terminology and Timestamp Highlighting
Given the Study Aid goal is selected When captions are generated from a transcript Then each caption segment includes a leading [mm:ss] timestamp synchronized within ±200 ms of the audio And up to 3 key terms per segment are emphasized using the goal’s emphasis style And no emojis are used; punctuation remains grammatical And highlighted terms do not exceed 30% of characters in the segment
Quote Reel Speaker Attribution Emphasis
Given the Quote Reel goal is selected and speaker diarization is available When a continuous quote of at least 2 seconds is captioned Then the first caption for that quote begins with the speaker’s display name followed by a colon, styled per goal And if the speaker’s name is unknown, a fallback label “Speaker N” is used And the speaker attribution line is not repeated within 5 seconds unless the active speaker changes And no emojis are used; quoted text is wrapped in quotation marks
Smart Goal-Aware Crop
"As a knowledge worker, I want the crop to adapt to my chosen goal so that important faces or slides stay in frame without manual keyframing."
Description

Implement subject-aware auto-reframing tuned per goal: vertical 9:16 with face priority for Promo and Quote Reel; 1:1 or 16:9 context-preserving crops for Recap; slide/board tracking for Study Aid. Use multi-signal saliency (face/pose, text-on-slide, motion) with shot-boundary detection to maintain subject centering and avoid jumpy framing. Respect safe regions for captions and brand elements, and fall back to pillar/letterboxing when needed. Provide lightweight per-goal rules to bias framing choices and ensure exports are ready for platform norms.

Acceptance Criteria
Promo & Quote Reel: 9:16 Face-Priority Reframing
Given a source video containing at least one detectable face and the user selects Promo or Quote Reel When Smart Goal-Aware Crop is applied Then the exported aspect ratio is exactly 9:16 and resolution >= 1080x1920 And the primary speaker’s face bounding box remains fully within frame with >= 10 px margin in 99% of frames And the face center remains within a centered 20% width x 20% height zone for >= 95% of frames per shot And no more than one reframing (pan/zoom) occurs within any 2-second window inside a shot And tie-breaks between saliency signals prioritize face > motion > text for this goal
Recap: Context-Preserving 1:1 or 16:9 Crop Selection
Given a source video with multiple salient regions and the user selects Recap When Smart Goal-Aware Crop is applied Then the selected aspect ratio per shot is 1:1 or 16:9 (no 9:16) and remains consistent within the shot And the chosen crop maximizes inclusion of the top-2 saliency regions (combined face/text/motion) with >= 90% of their area uncut per shot And the speaker’s face (if present) remains fully in-frame while preserving at least 50% of the largest context region And tie-breaks between saliency signals prioritize context/text > face > motion for this goal
Study Aid: Slide/Board Tracking with Text Priority
Given the user selects Study Aid and the source contains slides or a board with text When Smart Goal-Aware Crop is applied Then the crop includes >= 85% of the detected slide/board bounding box area in >= 95% of frames per shot And OCR-detected text regions (confidence >= 0.7) are not clipped by more than 5% of their area And if a pointing hand/laser appears within 15% of the crop edge, the crop recenters to include it within 300 ms without exceeding 10% zoom change per second And tie-breaks prioritize text/slide > face > motion for this goal And the aspect ratio is chosen between 16:9 or 9:16 based on slide orientation, with the shortest side >= 1080 px
Stability: Shot-Boundary Detection and Smooth Reframing
Given any goal and a multi-shot source video When Smart Goal-Aware Crop is applied Then reframing changes (hard cuts in crop center or scale) occur only within ±3 frames of detected shot boundaries unless the saliency centroid shifts > 20% of frame width for > 0.5 s And within a single shot, inter-frame crop center movement does not exceed 3% of frame width per second on average and 6% at any instant And zoom (scale change) does not exceed 10% per second on average and 20% at any instant within a shot And no visible crop jitter > 2 px between adjacent frames
Safe Regions: Captions and Brand Overlay Protection
Given goal-specific caption and brand overlay safe regions are defined (e.g., bottom 15% for captions, top-right 12% for logo) When Smart Goal-Aware Crop is applied Then faces and OCR-detected text (confidence >= 0.7) are kept outside these safe regions in >= 99% of frames And auto-captions and brand overlay do not overlap faces or high-saliency text regions; if conflict arises, the crop adjusts vertically by up to 10% to maintain separation And no essential content is placed within 8 px of frame edges where platform UIs may clip overlays
Fallback: Pillar/Letterboxing Without Critical Content Loss
Given the target aspect ratio cannot be achieved without cropping > 10% of the union of critical regions (faces + text + slide/board) in a shot When Smart Goal-Aware Crop is applied Then pillarboxing or letterboxing is used to meet the target aspect ratio while keeping 100% of critical region area visible And the box color/style follows goal defaults (blurred background or solid brand color) and is consistent across the export And the content remains centered with alignment error <= 2% of frame width
Export Readiness and Per-Goal Rule Biasing
Given any supported goal is selected When the export is generated Then the output adheres to goal norms: Promo/Quote Reel = 9:16, Recap = 1:1 or 16:9, Study Aid = 16:9 or 9:16 depending on slide orientation And the shortest side resolution is >= 1080 px and frame rate matches source within ±1 fps And per-goal saliency weights are applied: Promo/Quote Reel face:motion:text = 0.6:0.25:0.15; Recap context/text:face:motion = 0.45:0.4:0.15; Study Aid text/slide:face:motion = 0.6:0.25:0.15 And the export contains metadata indicating goal, chosen aspect ratio, and cropping mode for auditing

Clip Trio

Instantly delivers three distinct cuts—Hook, Context, and Takeaway—from your first upload. Each clip comes pre-captioned and timestamped so you can publish all three or pick a favorite in seconds, avoiding analysis paralysis.

Requirements

Auto Tri-Clip Generation Trigger
"As a new user, I want ClipSpark to automatically create the three clips from my first upload so that I get immediate value without setup or extra steps."
Description

On first upload into ClipSpark, the backend automatically orchestrates generation of three distinct clips—Hook, Context, and Takeaway—without requiring any additional user action. The pipeline sequences transcription, semantic segmentation, caption application, and render tasks, persisting outputs under the source asset with idempotent job control and progress events. It enforces input constraints (supported formats, max duration/size), handles concurrency via a queue, and tags resulting clips with source timestamps and confidence metadata for downstream display and export. It integrates with existing storage, model services, and authentication to ensure correct permissions and billing attribution.

Acceptance Criteria
Auto-triggered Tri-Clip on First Upload
Given an authenticated user with an active, billable workspace uploads a supported video file as their first asset to ClipSpark, When the upload completes and the asset is persisted, Then a tri-clip generation job is created automatically without any additional user action, And three target outputs are registered (Hook, Context, Takeaway) under the source asset, And each resulting clip has a unique ID and is stored in integrated storage, And the owner has read access to the clips and no unauthorized user can access them, And a single billable usage record is attributed to the correct workspace.
Job Lifecycle Progress Events Emission
Given a tri-clip job exists, When processing begins, Then progress events are emitted in order for states: queued, transcribing, segmenting, captioning, rendering, completed, And each event includes asset_id, job_id, state, timestamp, and percent_complete, And subscribers via API/WebSocket receive each event within 2 seconds of emission, And on completion, a final event includes the three clip IDs.
Pipeline Task Sequencing and Failure Guards
Given a tri-clip job, When tasks execute, Then transcription completes before semantic segmentation starts, And segmentation completes before caption application, And caption application completes before rendering, And each task success is recorded before the next begins, And if any task fails, Then the job status transitions to failed, no downstream tasks run, a retryable error code and message are recorded, and no partial clips are published.
Idempotent Job Control and Duplicate Suppression
Given an asset_id that already has a tri-clip job in progress or completed for the current asset version, When a duplicate trigger or retry request is received, Then the system returns the existing job_id and clip IDs without creating new outputs, And at most one active job exists per asset version, And reruns are only initiated when the asset version changes or an explicit regenerate operation is requested, And duplicate outputs are not persisted.
Input Constraints Enforcement and Error Responses
Given an upload that violates input constraints (unsupported container/codec, duration exceeds configured limit, or size exceeds configured limit), When the user attempts to upload, Then the system rejects the upload with a 4xx validation error including reason and limits, And no tri-clip job is created, And no billable usage is recorded, And any temporary storage is cleaned up within the defined retention window, And for a supported upload within limits, Then the job is accepted and processing begins.
Queue-based Concurrency Handling and Ordering
Given M concurrent first uploads where M exceeds the configured worker concurrency W, When tri-clip jobs are submitted, Then all jobs are enqueued, And no more than W jobs run simultaneously, And jobs start in FIFO order per workspace unless a higher-priority policy is configured, And no job is dropped or starved, And queue metrics expose depth and wait time for monitoring.
Clip Metadata Tagging and Persistence
Given tri-clip generation completes, When clips are persisted, Then each clip record includes clip_type (Hook|Context|Takeaway), source asset_id, start_time and end_time aligned to transcript within ±200 ms, caption files (SRT/VTT) and burned-in captions, and average and per-word confidence scores, And metadata is queryable via API, And exports include timestamps and confidence values, And downstream UI can display the tags and allow export without additional processing.
Hook/Context/Takeaway Detection Model
"As a content creator, I want the system to reliably identify the best Hook, Context, and Takeaway segments so that my clips feel cohesive and engaging."
Description

The system selects three non-overlapping, high-quality segments representing an attention-grabbing Hook, context-establishing background, and a succinct Takeaway by combining transcript semantics, prosody/visual change points, and engagement heuristics. It applies configurable length targets and bounds (e.g., 6–15s Hook, 15–45s Context, 8–20s Takeaway), deduplicates repetitive content, and ranks candidates by salience and clarity. The model outputs start/end timecodes, labels, and confidence scores, with fallbacks to heuristic selection when model confidence is low or content is short. It supports multilingual transcripts and domain tuning for educators, podcasters, and knowledge workers.

Acceptance Criteria
Triad Selection Integrity
Given a valid video with transcript duration >= 90s and default Clip Trio configuration When the Hook/Context/Takeaway detection model runs Then exactly three segments are returned labeled Hook, Context, and Takeaway And the three segments are strictly non-overlapping on the timeline ([start,end) intersection = 0 for each pair) And each segment’s start >= 0 and end <= video_duration with start < end And each label is unique and appears exactly once
Duration Targets and Bounds Compliance
Given default length bounds Hook: 6–15s, Context: 15–45s, Takeaway: 8–20s and optional per-label target durations When the model selects segments Then each segment duration falls within its configured min/max bounds (tolerance ±0.2s for rounding) And if per-label target durations are provided, the selected duration is within ±20% of the target while still honoring bounds And updating bounds in configuration is reflected in the next run without code changes
Confidence Thresholding and Heuristic Fallback
Given a configurable confidence threshold T (default T = 0.65) per label When the top semantic candidate for any label has confidence < T or content duration < sum of label lower bounds Then heuristic selection is used for that label (or for all labels if content is short) And the output marks fallback_used = true with fallback_reason in {low_confidence, short_content} And the system still returns up to three segments without overlap; if fewer than three are possible due to short content, the output explicitly indicates which labels are omitted and why
Content Deduplication Across Clips
Given the set of candidate segments per label When final Hook, Context, and Takeaway are selected Then the normalized token Jaccard similarity between transcripts of any two selected clips is < 0.50 And the embedding cosine similarity between any two selected clips is < 0.85 And there is no temporal overlap between any two selected clips
Multimodal Change-Point and Salience Alignment
Given detected transcript semantic topics, prosody/visual change-points, and engagement heuristics When selecting final segments Then at least two of the four boundaries (Hook start/end, Context start/end, Takeaway start/end) align within 1.0s of the nearest detected change-point And for each label, the chosen segment is salience-rank = 1 among candidates for that label And model decision logs for each selected segment include non-zero contributions from at least two signal classes in {transcript_semantics, prosody/visual, engagement}
Multilingual and Domain-Aware Operation
Given inputs with transcripts in English (en), Spanish (es), and German (de) When the model runs with language_code correctly provided Then three labeled clips are returned for each language with the same constraints satisfied as English And the output includes language_code matching the input and preserves diacritics/Unicode characters in captions And when domain is set to one of {educators, podcasters, knowledge_workers}, decision logs show a non-zero domain_weight and at least one selected clip changes for at least 2 of 3 test videos when switching domains
Output Schema Completeness and Timestamp Precision
Given the model completes a run When the results are returned via API Then each clip object includes {label, start_timecode, end_timecode, duration, confidence, rank, language_code, domain, fallback_used, fallback_reason?, model_version} And start_timecode/end_timecode precision is at least milliseconds and align to word boundaries within ±0.20s And the three clips in the payload are ordered by their start_timecode and pass JSON schema validation without warnings
Auto Captions with Word-Level Timestamps
"As an educator, I want accurate, timed captions on each clip so that my content is accessible and easy to index and share."
Description

Each generated clip includes accurate, synchronized captions derived from the source transcript with word-level timestamps, punctuation, and optional speaker attributions. Captions are baked into preview renders and provided as sidecar files (SRT, WebVTT) aligned to the clip-relative timeline, preserving source time references for cross-linking back to the full video. The system targets a defined accuracy threshold, supports profanity masking, and ensures accessibility with readable line lengths and contrast-safe styles. Language detection and translation hooks enable caption generation across supported locales.

Acceptance Criteria
Word-Level Timestamp Synchronization on Generated Clips
- Each generated clip includes per-word start_time_ms and end_time_ms aligned to the clip-relative timeline, covering ≥ 99% of transcribed words. - Median absolute word onset error ≤ 80 ms; 95th percentile ≤ 200 ms versus human-labeled reference on benchmark set. - No word has negative or zero duration; minimum duration ≥ 50 ms; adjacent words within a cue do not overlap; cumulative playback drift at clip end ≤ 100 ms. - Word timings used in preview render and exported timing data for the same clip differ by ≤ 50 ms for matching words.
Punctuation Accuracy in Caption Output
- Captions include sentence-ending punctuation (.?!), commas, and apostrophes consistent with source speech for supported locales. - Punctuation restoration achieves F1 ≥ 0.85 on the internal validation set; sentence boundaries align with cue boundaries in ≥ 95% of cases. - No duplicate punctuation, no space before closing punctuation, and locale-specific typography rules are applied (e.g., non‑breaking space before :;!? in fr‑FR). - Punctuation does not create orphaned characters at line breaks; line breaks occur at natural phrase boundaries in ≥ 90% of cues.
Optional Speaker Attribution Tagging
- When speaker labels are enabled, a label is added at each detected speaker change; when disabled, no labels appear in sidecars or burn-ins. - Diarization error rate (DER) ≤ 15% on multi-speaker clips; speaker change labeling latency ≤ 500 ms relative to actual change. - Speaker labels remain consistent for the same speaker within a clip; ≤ 1 mislabeled change per 5 minutes of audio. - WebVTT uses the "v" (voice) cue setting for labels; SRT uses a prefix (e.g., "Speaker 1:"); preview render displays labels with identical wording.
Sidecar Files Aligned to Clip Timeline with Source Time Mapping
- For every clip, SRT and WebVTT sidecars are generated with cue timecodes relative to clip start (00:00:00,000 / 00:00:00.000). - WebVTT includes an X-TIMESTAMP-MAP or NOTE header exposing the source absolute start time; SRT includes a NOTE header "SourceStart=hh:mm:ss,mmm". - Cue timing is monotonic with no overlaps; minimum cue duration ≥ 800 ms; maximum cue duration ≤ 6 s; maximum of 2 lines per cue. - Files pass WebVTT validation and load in common SRT parsers; playback in VLC and YouTube shows no timing shift beyond ±100 ms. - Computing source timestamps via the provided source start offset reproduces original video times within ±100 ms across the clip.
Burned-In Captions Meet Accessibility Standards
- Default theme achieves contrast ratio ≥ 4.5:1 between text and background on SDR content. - Max 2 lines per cue; max 42 characters per line on average; reading speed ≤ 17 characters/second; safe area margins ≥ 5% from frame edges. - Font height ≥ 4% of video height up to 1080p and ≥ 3% above 1080p; line spacing ≥ 120% of font size. - Placement avoids detected on-screen lower-thirds (name/title) when present; otherwise bottom-center. - 100% of sidecar cues appear in the preview render with start/end within ±100 ms of sidecar timing.
Profanity Masking Configurable and Consistent
- When masking is ON, profane terms from the active locale list are replaced with first letter + asterisks (e.g., "f***") in both sidecars and burn-ins; timing unchanged. - When masking is OFF, captions match the source transcript without masking; safe-listed words are never masked. - Masking preserves case on the first letter, adjacent punctuation, and spacing; no new tokens are introduced. - Detection recall ≥ 95% on curated profanity set for the locale; false positive rate ≤ 1% on a clean corpus.
Multilingual Detection and Translation Hooks
- Automatic language detection outputs a BCP 47 tag per clip; accuracy ≥ 95% on supported locales; unsupported locales return a clear error without generating captions. - When a target language is provided, captions are translated while preserving timestamps and cue boundaries; sidecar filenames or headers carry the target language code. - RTL languages render correctly in preview and WebVTT (dir=rtl or Unicode bidi marks applied); numerals and punctuation follow locale conventions. - Diacritics and non-Latin scripts are preserved in all outputs; UTF-8 encoding is used for sidecars. - Translation hook increases processing time by ≤ 20% compared to baseline captioning on a 30-minute input.
Instant Preview & One-Click Publish
"As a busy podcaster, I want to preview and publish all three clips with one click so that I can avoid decision fatigue and save time."
Description

The UI presents the three clips in a single, distraction-free panel with auto-play previews, durations, and labels, enabling users to publish all three or a selected favorite with a single action. Primary calls to action include Publish All, Publish Selected, and Download, with keyboard shortcuts and mobile-friendly controls to minimize decision friction. The flow shows live readiness states per clip, preserves selection between sessions, and writes publication status and destinations back to the asset record for auditability. Minimal optional edits (rename, thumbnail, visibility) are accessible but do not block instant publishing.

Acceptance Criteria
Unified Panel Auto-Play Previews With Labels and Durations
Given a processed asset has three generated clips When the Clip Trio panel loads Then exactly three clip cards labeled Hook, Context, and Takeaway are displayed in a single panel without modal overlays And each card displays its total duration in mm:ss And the preview for a card auto-plays within 500 ms when at least 50% of that card is visible in the viewport And the preview playback timestamps align to the clip duration within ±0.5 seconds
One-Click Publish All (Button and Shortcut)
Given all three clips are in Ready state and the Publish All control displays its keyboard shortcut in a tooltip When the user clicks Publish All or uses the displayed shortcut with the panel focused Then publication is initiated for all three clips to the asset’s configured destinations And the control shows an in-progress state within 200 ms And each clip transitions status from Ready → Publishing → Published upon API acknowledgment And each published clip displays its destination URL(s) once available
Publish Selected With Persistent Selection
Given the user selects one clip and the clip is in Ready state When the user refreshes the page, signs out, and signs back in within 30 days Then the same clip remains selected for that asset When the user activates Publish Selected (button or its displayed shortcut) Then only the selected clip is published And selecting a different clip deselects the prior selection (single-select enforced)
Live Readiness States and CTA Enablement
Given one or more clips are not Ready (Processing or Error) When the panel is displayed Then each clip shows a visible status: Ready, Processing, or Error with a live-updating indicator And Publish All is disabled until all three clips are Ready And Publish Selected is enabled only when the currently selected clip is Ready And hovering or tapping a disabled CTA reveals an explanation of the disabled condition
Publication Audit Write-Back to Asset Record
Given a publish action completes (success or failure) When the back end acknowledges the result Then the asset record is updated with an immutable audit entry including clip_id, action, destination(s), initiated_by, initiated_at (UTC), result_status, and destination_url(s) if applicable And the panel fetches and displays the audit data within 2 seconds of acknowledgment And if the write-back fails, a non-blocking warning with a Retry link is shown, and the publish is not auto-retried
Optional Edits Non-Blocking Instant Publish
Given optional fields Rename, Thumbnail, and Visibility are available in the panel When the user publishes without editing optional fields Then publishing proceeds immediately using defaults without additional prompts When the user edits any optional field Then Publish All and Publish Selected remain enabled And only the edited field is validated inline And invalid or incomplete optional input does not block publishing; the system either applies the last valid value or a safe default
Mobile-Friendly Controls and Download Behavior
Given a mobile viewport width of 375–414 px When the panel loads Then the three clip cards are vertically stacked with no horizontal scrolling And the primary CTAs (Publish All, Publish Selected, Download) are visible within one screen scroll and have tap targets ≥ 44x44 px And tapping Download downloads the selected clip; if none is selected, a ZIP of all three clips downloads And previews support tap play/pause with visible controls And all primary actions are completable without keyboard shortcuts
Multi-Format Export & Aspect Ratios
"As a social media manager, I want exports in multiple aspect ratios with readable captions so that I can post natively across platforms without re-editing."
Description

Each clip can be rendered into platform-ready presets with common aspect ratios (16:9, 9:16, 1:1), safe-area aware caption placement, and background treatment (blur, crop, pillarbox) to preserve subjects. Users can choose burned-in captions or sidecar delivery, with style templates that maintain brand consistency while ensuring legibility. Exports include embedded metadata (title, labels, source timestamps) and consistent file naming, and support direct handoff to connected destinations or local download. The rendering service reuses intermediate assets to minimize latency and cost.

Acceptance Criteria
Multi-Format Preset Export for Clip Trio
Given a Clip Trio (Hook, Context, Takeaway) exists for an uploaded video When the user selects Export Presets and chooses 16:9, 9:16, and 1:1 Then the system produces for each clip three MP4 files with pixel dimensions 1920x1080, 1080x1920, and 1080x1080 respectively And the original frame rate and audio sample rate are preserved And the output duration matches the clip within ±0.1 seconds And audio–video sync error is ≤ 50 ms And each export is labeled with the correct aspect ratio in the Export panel
Caption Safe-Area Placement Across Aspect Ratios
Given subject/face detection bounding boxes are available for the clip When captions are rendered for 16:9, 9:16, and 1:1 outputs Then captions remain within title-safe margins (side margins ≥ 5%; bottom margin ≥ 10% for 9:16 and ≥ 5% for 16:9/1:1) And captions do not overlap detected faces/subjects by more than 1% of the subject area And no caption text is clipped or rendered outside the frame And a maximum of 2 lines are shown per caption event; single-line enforced if line width would exceed 80% of frame width And minimum caption font size at 1080p is ≥ 42 px and scales proportionally with resolution And contrast ratio between text and background is ≥ 4.5:1
Background Treatment Preserves Subject
Given the user selects a background treatment (blur, crop, or pillarbox/letterbox) When exporting to each aspect ratio Then the primary subject bounding box is fully visible with a ≥ 12 px margin on all sides And if a crop would violate the margin, the system automatically falls back to pillarbox/letterbox for that frame And blur treatment applies a Gaussian blur of radius ≥ 20 px to the background only, without bleeding into the subject mask And the treatment color respects the template brand color when set, otherwise defaults to neutral black And no treatment introduces visible frame-to-frame flicker (background SSIM variance ≤ 0.02 across adjacent frames)
Caption Delivery Modes and Style Template Legibility
Given a style template is selected and a caption delivery mode is chosen When exporting a clip Then Burned-in mode renders captions into the video and produces no sidecar files And Sidecar mode produces .srt and .vtt files in UTF-8 with no burned-in text And caption timestamps align to the transcript within ±100 ms And the style template (font, color, outline/shadow, position) is applied consistently across all aspect ratios And legibility rules are enforced: contrast ≥ 4.5:1; stroke width ≥ 2 px at 1080p; line height ≥ 1.2× font size And if the specified font is unavailable, the defined fallback font is used and recorded in metadata
Embedded Metadata and Consistent File Naming
Given the clip has a title, labels, and known source timestamps When the export completes Then the video file embeds metadata fields: title, labels (comma-separated), source_start_ms, source_end_ms, template_id, clip_role And reading the file via ffprobe or exiftool returns non-empty values for these fields And the file name follows {projectSlug}_{clipRole}_{ratio}_{YYYYMMDD}-{HHmmss}_{clipId}.mp4 And file names contain only ASCII letters, numbers, dashes, and underscores; no spaces; length ≤ 80 characters And file names are unique within the project and sort lexicographically in chronological order for batch exports
Destination Handoff and Local Download
Given the user has connected one or more destinations When the user selects Send to Destination or Download for selected presets Then each destination upload starts automatically after render using current authentication and returns a success URL on completion And invalid or expired credentials trigger a re-authentication prompt without cancelling the export job And the UI shows render and upload progress with percentage and ETA; failures show actionable error codes and a retry option And a local download begins within 2 seconds of file readiness and the downloaded file hash matches the rendered asset
Intermediate Asset Reuse and Performance
Given a user re-exports the same clip segment with the same style template and caption mode but different aspect ratios or destinations When starting the second export within the cache TTL Then the renderer reuses intermediate assets (e.g., decoded audio, normalized transcripts, caption rasterizations) And median time-to-first-byte for the second export is at least 40% faster than the first And compute cost per export (internally tracked) is at least 30% lower when reuse applies And visual/audio parity with a full recompute path is maintained (video SSIM ≥ 0.98; audio peak difference ≤ 1 sample) And caches invalidate automatically when the source media, transcript, or style template version changes
Processing SLA & Failure Recovery
"As a knowledge worker, I want processing to be fast and resilient so that I can trust the feature to deliver useful clips even under load or when errors occur."
Description

The system meets an end-to-first-preview SLA suitable for “instant” perception, with progressive availability (first clip preview quickly, remaining clips streaming in as ready) and clear progress feedback. Autoscaling workers and prioritized queuing ensure first-time upload jobs are expedited, while backoffs and retries handle transient failures across transcription, segmentation, and rendering steps. Partial results are surfaced when components fail, accompanied by actionable error messages and a one-click regenerate option with adjusted parameters. Comprehensive logging, metrics, and alerts inform SRE and product dashboards for reliability tracking.

Acceptance Criteria
First Preview SLA with Progressive Availability
Given a first-time user uploads a video ≤ 90 minutes, ≤ 6 GB, ≤ 1080p and processing begins When the job is accepted by the system Then the first clip preview (Hook) is playable within 15 seconds at p95 and 30 seconds at p99 measured from upload completion And remaining Clip Trio previews (Context, Takeaway) appear progressively as each finishes, with all three available within 120 seconds at p95 and 240 seconds at p99 And each preview includes burned-in captions and correct timeline timestamps And the job records the measured times in metrics under "time_to_first_preview" and "time_to_all_previews"
First-Time Upload Prioritization Under Load
Given the worker pool is ≥ 80% utilized and there are queued jobs When a first-time user's initial upload job arrives Then the scheduler prioritizes it ahead of non-first-time jobs in the same queue And the prioritized job's queue wait time is ≤ 5 seconds at p95 and ≤ 15 seconds at p99 And its first preview SLA from the First Preview scenario is still met
Autoscaling to Maintain Queue SLAs
Given queue depth > 50 jobs for ≥ 60 seconds or p95 queue wait > 5 seconds When autoscaling evaluates capacity Then additional workers are provisioned within 2 minutes to restore p95 queue wait ≤ 5 seconds for 5 consecutive minutes And scale-in occurs only after queue depth < 10 for 10 continuous minutes and error rate remains ≤ 2% And no in-flight jobs are terminated during scale events
Transient Failure Retries with Backoff
Given a transient failure (HTTP 5xx, timeout, gRPC UNAVAILABLE) occurs in transcription, segmentation, or rendering When the step fails Then the system retries up to 3 times with exponential backoff starting at 2 seconds, capped at 30 seconds between attempts, with ±20% jitter And total retry time per step does not exceed 2 minutes And 4xx and explicitly non-retryable errors are not retried And failures in one clip's rendering do not block processing of the other clips
Partial Results, Errors, and One-Click Regenerate
Given one or more steps fail after retries When presenting results to the user Then successfully produced clips are immediately available and labeled "Partial — 2/3 ready" And an error banner includes a human-readable message, error code, and next-step suggestion And a single "Regenerate" action is visible with default adjusted parameters (e.g., alternate transcription provider, segmentation sensitivity −0.1, render resolution 720p) And clicking "Regenerate" reuses cached artifacts and only reprocesses failed steps, starting within 5 seconds at p95 And repeated clicks within 30 seconds are idempotent and create only one new job
Telemetry, Metrics, and Alerts for Reliability
Given any Clip Trio processing job When processing starts, progresses, retries, or ends Then structured logs are emitted with correlation IDs per job and per clip, stage name, start/end timestamps, duration ms, status, error code, and retry count And metrics are emitted for time_to_first_preview, time_to_all_previews, per-stage durations, queue_wait_time, success_rate, error_rate_by_stage, retry_count And dashboards display p50/p95/p99 for time_to_first_preview and success_rate over the last 24 hours And an alert pages SRE if p95 time_to_first_preview > 20 seconds for 5 consecutive minutes or error_rate_by_stage > 2% for 5 minutes And product dashboard highlights daily jobs impacted by failures and average regenerate success rate
User-Facing Stepwise Progress Feedback
Given a user uploads a video and processing begins When viewing the job detail or upload page Then a stepwise progress indicator displays current stage and ETA (Uploading, Transcribing, Segmenting, Rendering Hook/Context/Takeaway) And progress updates at least every 2 seconds and persists across page refreshes or reconnects And each clip becomes visible and playable immediately upon completion of its rendering step And labels show percent complete and count of completed/total clips And if a step is retrying, the UI shows "Retrying (n/3)" with an updated ETA

Next-Step Coach

A minimal, animated guide that highlights exactly one action at a time—Review, Tweak, Publish—so new users never stall. Micro-tooltips, progress ticks, and a live “under 3 minutes” timer keep momentum high and confusion low.

Requirements

Single-Action Spotlight
"As a first-time ClipSpark user, I want the interface to spotlight my single next action so that I can move forward without confusion."
Description

Provide a lightweight, animated coach overlay that illuminates exactly one primary action—Review, Tweak, or Publish—at a time while subtly dimming non-relevant UI. The spotlight attaches to the current step’s call-to-action, nudges attention with gentle motion, and remains non-blocking so power users can proceed normally. Includes minimize/close controls, remembers the last seen state per project, and gracefully adapts to different layouts and viewport changes.

Acceptance Criteria
Spotlight Anchors to Current Step CTA
Given the current step is 'Review' and the 'Review' CTA is visible in the viewport When the Single-Action Spotlight activates Then the spotlight ring aligns to the CTA bounding box with <=4px positional error on each edge And the spotlight position updates during scroll or container movement within one animation frame (<=16ms) of the CTA's movement And only one spotlight is visible at any time
Dim Overlay Is Non-Blocking
Given the spotlight is active When the user interacts with any non-highlighted, visible control (click, hover, keyboard) Then the interaction reaches the underlying control and executes its default behavior And the overlay does not intercept pointer or keyboard events except on spotlight UI and its controls And non-target UI is visually deemphasized by at least 30% while remaining legible
Minimize and Close Controls with Per-Project Persistence
Given the spotlight is active When the user activates the Minimize control via mouse or keyboard (Enter/Space) Then the coach collapses to a minimized state indicator and removes dimming within 200ms And focus returns to the previously focused element Given the coach is minimized on Project A When the user navigates away and returns to Project A Then the coach remains minimized Given the user activates the Close control When they return to Project A in a new session Then the coach remains closed and does not auto-open
Spotlight Updates on Step Transition
Given the current step is 'Review' When the step is marked complete and the next step becomes 'Tweak' Then within 300ms the spotlight reattaches to the 'Tweak' CTA And at no time are two CTAs highlighted simultaneously And the transition animation respects prefers-reduced-motion if enabled
Responsive Reflow and Viewport Change Handling
Given the spotlight is active When the user resizes the window, changes orientation, or triggers a layout reflow (e.g., sidebar toggle) Then the spotlight remains attached to the correct CTA with <=4px positional error And if the CTA leaves the viewport, the spotlight hides and reappears within 100ms of the CTA re-entering the viewport And no visual artifacts (double shadows, misaligned mask, clipped edges) persist after reflow
Accessibility and Assistive Technology Support
Given a user navigates via keyboard or screen reader When the spotlight is active Then all coach controls are reachable in logical tab order, have visible focus, and are operable with Enter/Space And the highlighted action is announced to assistive tech with an accessible name that includes the action label (e.g., 'Review') And the overlay meets WCAG 2.1 AA contrast requirements on light and dark themes And if prefers-reduced-motion is enabled, pulsing/animated effects are disabled while functional cues remain
Last-Seen Step Restoration Per Project
Given a user leaves Project B while the current step is 'Tweak' and the spotlight is attached to the 'Tweak' CTA When the user returns to Project B later Then the coach restores the 'Tweak' step as current and reattaches the spotlight to the corresponding CTA And if the CTA is not immediately present due to layout or data loading, the coach attaches within 200ms of the CTA becoming available
Progress Ticks & State Persistence
"As a new user, I want to see clear progress through Review, Tweak, and Publish so that I know how close I am to finishing."
Description

Display a three-step status with checkmarks that update in real time as the user completes Review, Tweak, and Publish. Persist progress per project across sessions and devices, and automatically revalidate when upstream changes invalidate a step, providing a brief rationale when a completed step is unchecked. Provide a compact progress bar in the coach and a secondary indicator near the timeline so users always know where they are.

Acceptance Criteria
Real-Time Tick Updates On Step Completion
Given a project with steps Review, Tweak, Publish and the user is viewing it in the coach When the user clicks "Mark Review Complete" Then the Review step displays a checked tick within 500 ms without page reload And the Tweak step becomes the active step in the coach And the secondary timeline indicator reflects Review as completed within 500 ms
Cross-Session and Cross-Device Progress Persistence
Given the user is signed in and has completed the Review step on Device A When the same project is opened on Device B while signed in to the same account Then the coach ticks and the timeline indicator show Review as completed on initial load And after sign-out/sign-in and a hard page refresh, the completed state remains unchanged And reopening the project after 24 hours still shows the same completion state
Automatic Revalidation On Upstream Changes
Given Tweak is marked Complete When the user edits the timeline or source assets in a way that changes content used by Tweak Then Tweak is automatically unchecked within 1 s And Publish is also unchecked if it depends on outputs from Tweak And the coach focuses the earliest invalidated step
Brief Rationale Shown When Step Becomes Unchecked
Given a step changes from Complete to Incomplete due to revalidation When the UI updates the step to unchecked Then a brief rationale is displayed adjacent to the step for 5–10 seconds And the rationale text is <= 120 characters and includes cause and timestamp (e.g., "Transcript updated 14:32") And the rationale is accessible via tooltip and announced via aria-live
Compact Progress Bar In Coach Shows Three-Step Status
Given the coach panel is visible When the project is loaded Then a compact progress bar with three labeled segments (Review, Tweak, Publish) is displayed And completed segments show a checkmark, the active segment is visually highlighted, and future steps are muted And the bar height is <= 24 px and fits within the coach without horizontal scroll
Secondary Timeline Indicator Mirrors Progress State
Given the timeline view is visible When any step is completed or invalidated Then the secondary indicator near the timeline updates to the same state as the coach within 500 ms And the indicator remains visible without overlapping timeline controls at common viewport widths (>= 1024 px) And hovering the indicator reveals the same rationale tooltip for invalidation events
Consistent State Across UI Components And API
Given a project ID with step states When the client fetches step status from the backend Then the API returns Review, Tweak, Publish states that match what the UI displays And state changes on one client propagate to another active client within 3 seconds And concurrent updates resolve deterministically using server timestamp precedence
Micro-Tooltips Engine
"As a learning user, I want brief tooltips explaining the next click so that I understand what to do without reading documentation."
Description

Render concise, context-aware tooltips for the active step that appear on hover, focus, or brief inactivity. Tooltips explain the purpose of the step and the immediate next click in one or two short lines, include an optional “Learn more” link, and never obstruct the target element. Hints are rate-limited, dismissible, respect user preferences, and default to being shown for new users.

Acceptance Criteria
Active Step Tooltip Triggers
Given the Next-Step Coach has an active step with a visible, enabled target element When the user hovers the target for at least 300 ms Then a tooltip for that step becomes visible within 150 ms And When the target receives keyboard focus via keyboard navigation or programmatically Then the tooltip becomes visible within 150 ms And When there is no pointer or keyboard activity on the active step for 1200 ms (±300 ms configurable) Then the tooltip becomes visible And Only one tooltip is visible at any time And No tooltip is shown for inactive steps or non-Coach UI elements And Tooltips do not appear if the target is disabled, hidden, or off-viewport
Tooltip Content and Link Rules
Given a tooltip is visible for an active step Then the tooltip body contains one or two lines totaling no more than 160 characters And The content states the step’s purpose and the immediate next click/action And Text wraps without horizontal scrolling; no content overflows the container And If a help URL is configured, a single “Learn more” link is rendered; otherwise no link is shown And The “Learn more” link is keyboard-focusable, opens in a new tab (target=_blank, rel=noopener noreferrer), and has an accessible name And Localization uses the user’s locale; if unavailable, English is used
Non-Obstructive Placement and Viewport Safety
Given a tooltip is about to be shown for a target element When positioning is computed Then the tooltip does not overlap the target element’s bounding box by ≥ 1 CSS pixel And The tooltip maintains an 8 px gap from the target and stays fully within the viewport with an 8 px margin And If a non-overlapping, in-viewport placement is not possible, the tooltip is not shown and a placement_unavailable event is logged And Pointer interactions with the target are not intercepted by the tooltip (clicks on target succeed) And The tooltip auto-flips among top/bottom/left/right placements to preserve non-obstruction And Layering ensures the tooltip appears above page content and Coach highlights but below modal dialogs
Dismissal Behavior and State Persistence
Given the tooltip is visible When the user clicks the close control, presses Escape, clicks outside, or completes the prompted action on the target Then the tooltip hides within 150 ms without causing layout shift And The dismissal reason is recorded And The tooltip for that step remains dismissed for the remainder of the session unless the user re-triggers it after a 30-second cooldown or explicitly opens help And No JavaScript errors are logged during show/hide
Rate Limiting and Anti-Nagging
Given repeated trigger conditions for the same step Then the tooltip is not shown more than once every 30 seconds for that step And Across all steps, no more than 3 idle-triggered tooltips are shown in any rolling 10-minute window And A tooltip dismissed by the user does not reappear for at least 5 minutes unless the user navigates away and returns after completing another step And Rate limits reset when the session ends
User Preferences and New-User Default
Given a new user (first 3 sessions or account age < 7 days) Then tooltips are enabled by default And Given a user disables tooltips in preferences Then no tooltips render for any trigger (hover, focus, inactivity) And Preference changes take effect immediately and persist across sessions and devices within 60 seconds And When tooltips are disabled, no tooltip-related network calls or renders occur
Accessibility: Keyboard, Screen Reader, and Motion
Given a target has an associated tooltip Then the tooltip uses role=tooltip and is referenced by aria-describedby on the target And When the target receives focus, the tooltip text is announced once by screen readers (polite) And If the tooltip contains a “Learn more” link, it is reachable via Tab immediately after the target; otherwise the tooltip is not focusable And Pressing Escape while the tooltip or its link is focused dismisses the tooltip and returns focus to the target And Tooltip text and background meet a contrast ratio of at least 4.5:1 And When prefers-reduced-motion is enabled, animations are disabled or ≤ 100 ms; otherwise open/close animations are ≤ 150 ms
Live Under-3-Min Timer
"As a busy professional, I want a live under-3-minute timer so that I can gauge time and stay on track."
Description

Show a live countdown targeted at three minutes or less for completing the flow. The timer starts when the coach appears, pauses on inactivity or blocking dialogs, resumes on interaction, and subtly shifts color as time elapses to maintain momentum without pressure. If step complexity changes, adjust remaining time accordingly while preserving the "under 3 minutes" framing for typical paths.

Acceptance Criteria
Timer Starts with Coach Visibility
Given the Next-Step Coach becomes visible to the user for a new flow When the coach UI renders on screen Then the countdown initializes to 2:59 and begins decrementing within 300 ms And the display updates once per second with jitter ≤ ±200 ms And the timer is visible and labeled to assistive tech via an aria-live="polite" region announcing the initial remaining time
Timer Pauses on Inactivity
Given the user has not interacted (no keyboard, pointer, or touch input) for 5 consecutive seconds and no coach step change has occurred When the inactivity threshold is reached Then the countdown pauses within 300 ms and stops decrementing And a non-flashing paused indicator is shown next to the timer And the elapsed/remaining time is preserved while paused
Timer Pauses on Blocking Dialog
Given a blocking modal or system overlay is opened (e.g., aria-modal="true" or interaction with the coach is disabled) When the dialog becomes active Then the countdown pauses within 300 ms and stops decrementing And the timer remains paused until the blocking dialog is dismissed
Timer Resumes on Interaction
Given the countdown is paused due to inactivity or a blocking dialog When the user performs a valid interaction with the coach (e.g., click Review/Tweak/Publish controls or keyboard activates a coach action) and no blocking dialog is present Then the countdown resumes within 300 ms And total elapsed time excludes all paused intervals (no seconds are deducted while paused) And updates continue at one-second intervals with jitter ≤ ±200 ms
Subtle Color Shift Over Time
Given the countdown is running When time elapses through defined thresholds (e.g., >120s remaining, 119–61s, ≤60s) Then the timer color shifts progressively across at least two distinct states with smooth transitions (no flashing, transition duration ≥ 300 ms) And the color contrast against its background is ≥ 3:1 in each state And the design avoids alarming cues (no red flashing, no animation > 3 Hz) while remaining noticeable
Dynamic Adjustment for Step Complexity
Given the remaining time estimate is based on the active step and selected options When the user changes options that increase or decrease step complexity Then the remaining time recalculates within 500 ms to reflect the new estimate And the numeric display never shows 3:00 or higher (maintains an "under 3 minutes" framing) And for the typical path (default Review → Tweak → Publish with no optional heavy operations), the remaining time never exceeds 2:59 at any point And when complexity decreases, the remaining estimate decreases; when complexity increases, the estimate increases
Context-Aware Step Sequencing
"As a user moving between tasks, I want the coach to take me to the correct next step based on my project’s state so that I don’t waste time guessing."
Description

Detect project state to select and present the next most relevant step. Automatically route users to Review once captions are generated, to Tweak after initial approval, and to Publish when export prerequisites are met. Disable unavailable actions with a short reason and an action to satisfy prerequisites, preventing stalls and ensuring the coach always points to a valid next step.

Acceptance Criteria
Auto-route to Review after captions are generated
Given a project where captionsReady=true and initialApprovalRecorded=false When the Next-Step Coach detects the captionsReady state (via event or poll) Then the coach highlights "Review" as the single primary action within 2 seconds And the UI routes/focuses to the Review view within 1 second of the highlight change And "Tweak" and "Publish" are disabled with reasons: "Approve captions first" and "Complete Review first"
Advance to Tweak after initial approval in Review
Given the user clicks "Approve Captions" on the Review step and the server persists approval (HTTP 200) When the approval response is received Then the coach highlights "Tweak" as the single primary action within 1 second And the UI routes/focuses to the Tweak view without reload And "Review" shows a completed tick and is no longer primary And "Publish" remains disabled with reason: "Finish tweaks and export settings"
Enable Publish only when export prerequisites are met
Given captionsApproved=true And exportPrereqsMet=true (e.g., at least one output selected and required export fields validated) When the Next-Step Coach evaluates step eligibility Then the coach highlights "Publish" as the single primary action within 2 seconds And the UI routes/focuses to the Publish view upon user click And if exportPrereqsMet=false at any time, "Publish" is disabled with a concise reason listing missing items
Disabled actions show short reason and a Fix action
Given any step button is disabled due to unmet prerequisites When the user hovers or taps the disabled step Then a tooltip/sheet appears within 300 ms with a reason ≤ 90 characters And the tooltip includes a "Fix" action that navigates directly to the first missing field/section And keyboard users can activate the Fix action via Enter/Space and focus lands on the target control And once the prerequisite is satisfied and saved, the previously disabled step enables within 1 second
Real-time recompute of next step on backend state changes
Given the project state changes server-side (e.g., captionsReady flips, export validation passes) When the client receives the update (push or poll) Then the coach recalculates and updates the highlighted next step within 2 seconds without full-page reload And previously primary steps are demoted so that exactly one primary action remains And no dead-end state is shown (there is always either an enabled primary step or a Fix action available)
Only one action is highlighted at any time
Given any project state When the Next-Step Coach renders or updates Then exactly one of {Review, Tweak, Publish} is marked as the primary action (e.g., data-primary=true, aria-current="step") And all other steps are non-primary and, if ineligible, disabled with reasons And visual animation does not trigger for more than one step simultaneously
Accessible & Localized Coach
"As a user who relies on accessibility features or a non-English language, I want the coach to be keyboard- and screen reader-friendly and localized so that I can use it comfortably."
Description

Meet WCAG 2.2 AA with full keyboard navigation, visible focus states, ARIA roles, and polite live-region announcements for step changes and timer updates, plus reduced-motion alternatives. Localize all strings and time formats, support RTL layouts, ensure high contrast, and allow scalable typography so the coach remains clear and comfortable across devices and languages.

Acceptance Criteria
Keyboard-Only Navigation Through Next-Step Coach
- All interactive coach elements are reachable via Tab/Shift+Tab in logical order: Open Coach trigger → Step header → Primary action → Secondary action → Close/Dismiss. - Enter/Space activates the focused control; Esc closes the coach and returns focus to the Open Coach trigger. - No keyboard trap: focus cycles within the coach only when aria-modal="true"; otherwise, Tab/Shift+Tab proceed to the next/previous page element. - On step change, programmatic focus moves to the new step’s heading within 500 ms. - Arrow keys navigate within any composite widget (e.g., progress ticks) per WAI-ARIA Authoring Practices. - All shortcuts and key behaviors are documented in an accessible help tooltip reachable via keyboard.
Visible Focus States and Accessible Contrast
- Each focusable element displays a visible focus indicator with at least 3:1 contrast against adjacent colors and a minimum 2px outline or equivalent thickness. - Body text and control labels meet 4.5:1 contrast (normal text) and 3:1 (large text ≥18pt or 14pt bold). - Progress state is not conveyed by color alone; an icon, pattern, or text label is present. - Focus indicator remains clearly visible in both light/dark themes and in OS high-contrast modes. - No element suppresses focus outlines via CSS unless replaced with an equivalent or better custom indicator.
ARIA Roles, Names, and Polite Live Announcements
- Coach container exposes an accessible name and appropriate role (dialog or region); if modal, aria-modal="true" is set. - All interactive controls have programmatic names that match or include visible labels; states (pressed, selected, disabled) are exposed via ARIA. - Step changes announce once via a single aria-live="polite" region as: "Step {n} of {total}: {StepName}" within 500 ms of change; no duplicate announcements. - Timer updates announce no more than once every 30 seconds and additionally at T-10s and T-0 using aria-live="polite"; announcements do not interrupt ongoing screen reader speech. - Accessibility scans (axe/lighthouse) report zero critical ARIA violations within the coach.
Reduced Motion Alternatives for Coach Animations
- When prefers-reduced-motion is detected, animations are removed or reduced to non-essential fades ≤100 ms; no parallax or motion-based transitions occur. - An in-app "Reduce motion" toggle is available and, when enabled, disables all non-essential animations; the choice persists for the session. - No essential information is conveyed solely through motion; equivalent static cues (text/icon) are provided. - Animated elements do not loop indefinitely under reduced-motion settings.
Localization of Strings, Time, and Number Formats
- All user-facing strings are externalized and fully localized for en-US, es-ES, and ar-SA; no hardcoded English remains for these locales. - Time and numbers render with locale-appropriate digits and formats (e.g., 12/24-hour, RTL numerals for ar-SA). - ICU MessageFormat handles pluralization and variable insertion (e.g., "under 3 minutes") correctly per locale. - Pseudo-localization (+30% length, accented characters) displays without truncation or overlap at 320px width. - Changing locale at runtime updates all coach strings and formats within 200 ms without page reload.
Right-to-Left (RTL) Layout Support
- When an RTL locale is active, the coach layout, step progression, and chevron/icons mirror horizontally; dir="rtl" is applied at the coach root. - Reading and keyboard focus order follow the visual right-to-left order. - Tooltips, callouts, and progress ticks anchor and position correctly in RTL without clipping or overlap. - Screen readers use the correct language and directionality via lang and dir attributes.
Scalable Typography and Responsive Reflow
- At 200% text size (OS) and 400% browser zoom, all coach content remains readable and functional with no loss of information. - No horizontal scrolling is required at viewport widths ≥320 CSS px; content reflows vertically as needed. - Touch targets are ≥44x44 CSS px at all scales. - Micro-tooltips, timer, and buttons remain within the viewport and do not overlap or clip adjacent content.
Engagement Analytics & Funnel
"As a product team member, I want analytics on coach engagement so that we can improve the flow and reduce drop-off."
Description

Instrument coach interactions with structured events—coach_started, step_shown, tooltip_displayed, tick_completed, timer_paused, publish_clicked, coach_dismissed—and stream to the analytics pipeline with project and cohort metadata. Provide a basic funnel dashboard showing completion rates, time-to-publish, and drop-off points, and trigger alerts when drop-off exceeds thresholds to guide iteration.

Acceptance Criteria
Event Instrumentation and Schema Coverage
Given analytics are enabled for a project and a user launches the Next-Step Coach When the user progresses through Review → Tweak → Publish and interacts with tooltips, ticks, timer, and dismissal Then the following events are emitted and received once per occurrence with valid payloads: coach_started, step_shown (per step), tooltip_displayed (on tooltip open), tick_completed (per tick), timer_paused (on pause), publish_clicked (once), coach_dismissed (on dismiss) And each event includes required fields: event_id (UUIDv4), occurred_at (ISO-8601 UTC), project_id, user_id_hashed, session_id, coach_version, cohort_tags[], app_version, device, locale And step_shown includes: step_key ∈ {review,tweak,publish}, step_index, is_last_step And tooltip_displayed includes: tooltip_id, step_key And tick_completed includes: step_key, tick_index, total_ticks And timer_paused includes: elapsed_ms, remaining_ms, timer_started_at And publish_clicked includes: time_to_publish_ms, steps_completed_count And coach_dismissed includes: reason ∈ {user_close,inactivity,completed,other} And schema validation failure rate < 0.5% over 1,000 sessions and missing required fields = 0
Reliable Event Streaming and Ordering
Given intermittent connectivity conditions When events are generated offline Then events are queued locally and delivered on reconnect within 60s, preserving per-session order via sequence_number And end-to-end delivery latency p95 ≤ 5s and p99 ≤ 15s under normal load And duplicates are suppressed using idempotency_key; effective duplicate rate in the warehouse ≤ 0.1% And retries use exponential backoff for up to 24h; after max retries, events are written to a dead-letter queue with reason And server acknowledgements (HTTP 202) are returned for accepted batches and health endpoint /analytics/health returns status=ok
Funnel Dashboard Accuracy and Filtering
Given a 14-day default date range and cohort=All When the dashboard loads Then it shows funnel from coach_started → publish_clicked with step-level drop-off %, overall completion rate, and time-to-publish (median, p75, p95) And dashboard totals match the analytics store within ±1% And filters (date range, project_id, cohort tag, coach_version) update all widgets consistently within 2s p95 And a drop-off table lists the top 3 steps by drop-off with % and absolute counts And with the QA fixture dataset applied, the dashboard renders expected values (e.g., completion 62%, median TTP 2m10s, drop-off after tweak 21%)
Drop-off Alerting and Notification
Given a configurable drop-off threshold per cohort (default 25% at any step over a 24h rolling window with N≥100 sessions) When the computed drop-off exceeds the threshold Then an alert is sent within 5 minutes to configured channels (email, Slack webhook) including: project_id, cohort, step_key, drop-off %, baseline %, window, N, and a deep link to the dashboard And alerts are suppressed if unchanged for 2h and re-notified only on ≥10% relative change or on resolution And a resolution notice is sent when the metric returns below threshold for one full window And misconfigured channels surface actionable errors without blocking metric computation
Consent, Privacy, and Data Governance
Given a user has not granted analytics consent or a project-level analytics opt-out is enabled When the Next-Step Coach is used Then no analytics events are emitted or stored and the dashboard excludes this traffic And user identifiers are hashed client-side (SHA-256 + salt); no raw PII leaves the device And event metadata excludes video content or transcript text; only IDs and numeric timings are collected And data retention enforces raw events TTL=180 days and aggregates TTL=365 days; deletions propagate within 7 days And user deletion requests remove associated raw and aggregated data within 7 days
Operational Monitoring and Backpressure Handling
Given the analytics pipeline is running When observing system telemetry Then metrics are exposed: ingest_q_depth, e2e_latency_ms, error_rate, dlq_size, events_per_minute with p50/p95/p99 views And on ingest_q_depth > 10,000 for >5 minutes or error_rate > 1% for >1 minute, an on-call alert is fired And client backpressure drops non-critical events (tooltip_displayed) when local queue > 5,000 while preserving critical events (publish_clicked, coach_started) And daily reconciliation between client-counted and server-received events is within ±2%

Persona SnapStart

Choose a quick persona (Podcaster, Educator, Sales, Research) and Fastlane applies proven defaults—clip runtime, jargon-aware captions, safe margins, and export settings—so your first results feel tailored and accurate without setup.

Requirements

Persona Catalog & Defaults Engine
"As a new user, I want to pick a persona and have sensible defaults applied automatically so that my first output is tailored without manual setup."
Description

Implements a centralized, versioned catalog of predefined personas (Podcaster, Educator, Sales, Research) and their default parameters, including clip runtime ranges, caption rules (jargon handling, acronym expansion, reading speed), highlight heuristics weights, safe margins, export presets, and summary tone. Provides a JSON-schema–backed configuration service with remote fetch, local cache, and safe fallbacks so the app can resolve a persona to a concrete, ready-to-apply setting bundle at project creation or on demand. Supports extensibility for new personas, environment- or tenant-level overrides, and A/B testing of defaults. Exposes typed APIs for read/apply/compare operations and guarantees backward compatibility via schema versioning.

Acceptance Criteria
Persona Resolution at Project Creation
Given the app is online and the user selects the Podcaster persona during project creation When the configuration service resolves the persona Then it returns a setting bundle conforming to the current supported schema version with required keys: clip_runtime_range, caption.rules(jargon_handling, acronym_expansion, reading_speed_wpm), highlight.weights, safe_margins, export.presets, summary.tone And clip_runtime_range.min and .max are within persona-defined bounds (min < max, both numeric in seconds) And caption.reading_speed_wpm is within 120–220 wpm and acronym_expansion is boolean And highlight.weights are numeric in [0.0,1.0] and sum to ≤ 1.0 if normalized And safe_margins are non-negative timecodes And export.presets include at least one of {mp4_1080p, mp4_720p} And summary.tone equals the persona default (e.g., "conversational" for Podcaster) And the bundle is returned within 300 ms p95 on a warm cache
Remote Fetch, Local Cache, and Safe Fallbacks
Given the device is online and a persona bundle is requested When the remote catalog is reachable Then the latest compatible persona bundle is fetched, validated, cached with a TTL (configurable, default 24h), and returned Given the device is offline and a persona bundle is requested When a valid cached bundle exists and is not expired Then the cached bundle is returned and a background refresh is scheduled on reconnect Given the device is offline and no valid cache exists When a persona bundle is requested Then the baked-in fallback bundle matching the last known compatible schema version is returned and a warning event is logged And in all cases, failures to fetch do not block project creation
Backward-Compatible Schema Versioning
Given the app supports schema versions v1..vN and the catalog serves vN+1 with additive fields When the app fetches a persona bundle at vN+1 Then unknown fields are ignored, known fields are parsed, and required fields missing in vN+1 are backfilled by defaults And the resolved bundle passes validation and is applied without runtime errors And a telemetry event records schema_mismatch=true and mapped_version=vN Given the catalog serves a bundle at an unsupported lower version (<v1) When the app fetches the bundle Then the app rejects it, uses the last known good cache or fallback, and logs an error with code CONFIG_VERSION_UNSUPPORTED
Overrides Precedence and Deterministic Merge
Given base persona defaults, environment-level overrides, and tenant-level overrides are defined When resolving a bundle for a tenant Then precedence is tenant > environment > base And only keys present in overrides replace base; unspecified keys inherit And invalid override keys are ignored with a warning and do not affect other keys And the final merged bundle is deterministic: resolving the same inputs yields byte-identical JSON And a diff of (final vs base) lists only overridden keys with their source layer
Typed APIs for Read, Apply, and Compare
Given a client integrates the configuration SDK When calling readPersona(personaId, options) Then the SDK returns a strongly-typed PersonaBundle or a structured error with code and remediation When calling applyToProject(projectId, bundle) Then the project’s settings are updated atomically and a success result with applied_version and checksum is returned When calling compareBundles(a,b) Then the SDK returns a diff object listing added, removed, and changed paths with old/new values And passing an invalid bundle shape causes validation errors before network calls And all API calls are idempotent and have p95 latency ≤ 200 ms locally (cache hit) and ≤ 600 ms on remote fetch
Extensibility: Add New Persona Without App Update
Given a new persona "Research" is added to the catalog conforming to the current schema When the app fetches the persona list Then "Research" appears with metadata (id, label, version) and can be resolved to a valid bundle And UI surfaces the persona via Persona SnapStart without requiring an app release Given a client requests an unknown persona id When readPersona is called Then the SDK returns error code PERSONA_NOT_FOUND and suggests available ids
A/B Testing of Persona Defaults
Given an experiment "podcaster_clip_runtime_v2" with variants A and B is active at 50/50 When an eligible user requests the Podcaster persona Then the assignment is stable per user (consistent for 30 days or until experiment ends) and included in the response (experiment_id, variant) And the returned bundle reflects the variant-specific defaults (e.g., clip_runtime_range differs) And disabling the experiment reverts all users to control (A) on next fetch And assignment and exposure events are logged exactly once per session
SnapStart Persona Selector UI
"As a time-pressed creator, I want a simple persona selector that shows what will change so that I can apply the right defaults with confidence in one click."
Description

Delivers an accessible, one-click persona picker available during project creation and within the editor toolbar. Displays concise previews of what changes will be applied (e.g., clip length, caption style, export targets) and provides contextual tips. Triggers non-blocking application of defaults via the engine, with visual feedback and error handling. Handles existing-project scenarios with a merge prompt that shows which fields will change and preserves user-locked fields. Fully keyboard- and screen-reader–navigable and responsive across desktop and mobile.

Acceptance Criteria
Project Creation: One-Click Persona Picker
Given the user is in the new project creation flow When the persona picker loads Then the options "Podcaster", "Educator", "Sales", "Research" are visible as individual, clickable controls with accessible names And no option is pre-selected When the user clicks or taps any option Then that option becomes selected within 100 ms and is visually indicated And the selection is persisted to the pending project configuration
Editor Toolbar: Persona Picker Availability
Given an existing project is open in the editor When the toolbar is displayed Then a persona picker control is present, labeled "Persona", and shows the current persona if set or "None" When the user opens the control and selects a persona Then the control closes and reflects the selected persona
Persona Preview of Applied Changes
Given any persona option is focused, hovered, or its info is expanded When the preview panel is shown Then it lists the values that will change: clip runtime, caption style, safe margins, and export targets And the displayed values match the persona's configuration data exactly And a contextual tip (<= 140 characters) is displayed And no project settings are changed until the user selects the persona
Apply Defaults: Non-Blocking With Visual Feedback
Given the user selects a persona from the picker When defaults are being applied by the engine Then the UI remains interactive and no blocking modal is shown And a progress indicator appears within 200 ms of selection And on success, a toast appears within 200 ms of completion summarizing the number of fields updated And the current persona label in the UI updates to the selected persona
Apply Defaults: Error Handling and Recovery
Given an engine error occurs while applying persona defaults When the error is detected Then a non-blocking error toast appears with a human-readable message and a "Retry" action And any partially applied changes are rolled back to the previous values And the error is logged with a correlation ID When the user clicks "Retry" and the engine succeeds Then the success toast is shown and changes are applied
Existing Project: Merge Prompt With Locked Fields Preservation
Given the user selects a persona on a project with existing settings And some fields are marked as user-locked When the merge prompt appears Then it lists all fields that would change with their current and new values And locked fields are labeled "Locked" and are excluded from change by default And the user can deselect individual fields to exclude them from the apply When the user confirms Then only selected, unlocked fields are updated And locked and deselected fields remain unchanged And the confirmation summary shows the count of fields changed And if there are no differences between current settings and the persona defaults, no merge prompt is shown
Accessibility and Responsiveness Compliance
Given keyboard-only navigation When interacting with the persona picker and merge prompt Then all interactive elements are reachable in a logical order, have visible focus states, and can be activated using Enter/Space And screen readers announce control labels, states, and changes (including toasts) via appropriate roles and aria-live regions And contrast ratios meet WCAG 2.1 AA Given a 320px wide mobile viewport and a 1024px desktop viewport When the UI is rendered Then no horizontal scrolling is required, controls are not truncated, and tap targets are at least 44x44 px
Jargon-Aware Captioning Profiles
"As an educator or podcaster, I want captions that respect my field’s jargon and readability norms so that viewers get accurate, easy-to-follow subtitles."
Description

Introduces persona-specific captioning profiles that inject domain glossaries, acronym expansion rules, profanity handling, and line-length/words-per-minute targets into the ASR and post-processing pipeline. Integrates with diarization and timestamping to maintain accuracy while respecting reading speed and line breaks. Allows per-persona toggles (e.g., expand first mention only, keep industry terms) and supports multilingual glossaries. Measures quality via WER and formatting metrics, with automated regression checks. Falls back gracefully to generic captions if a profile is unavailable.

Acceptance Criteria
Persona Profile Defaults Applied During ASR
Given the user selects a Persona SnapStart persona (Podcaster, Educator, Sales, or Research) before uploading a video When the ASR and caption post-processing pipeline executes Then the job's profileSnapshot.personaId equals the selected persona And the profileSnapshot includes keys [lineLength, wpmTarget, profanityMode, acronymMode] And each key's value equals that persona's configured defaults for the selected locale And automated tests verify this mapping for all four personas (4/4 pass)
Domain Glossary Injection Accuracy
Given a persona with an active domain glossary and a labeled evaluation clip containing N annotated glossary term occurrences When captions are generated Then at least 95% of annotated glossary terms are rendered exactly as their glossary canonical forms (term-level recall >= 95%) And no glossary term appears in captions without being spoken (precision >= 98%) And case/diacritics match the glossary specification for >= 98% of matched terms
Acronym Expansion Rules and Toggles
Given acronym rules with toggles [expandFirstMentionOnly, alwaysExpand, keepIndustryTerms] When processing a transcript containing at least one acronym with a known long form Then with expandFirstMentionOnly=ON, the first occurrence is "Long Form (ACRONYM)" and all subsequent occurrences are "ACRONYM" (0 violations) And with alwaysExpand=ON, all occurrences are expanded to the long form (0 violations) And when keepIndustryTerms contains an acronym, that acronym is preserved verbatim even on first mention (0 violations)
Profanity Handling Modes per Persona
Given a persona default profanityMode in {mask, bleep, allow} and an input containing profane tokens from the supported lexicon When captions are generated Then for mask, each profane token is rendered as firstLetter + asterisks of equal length (100% masked; 0 leaks) And for bleep, each profane token is replaced by "[BLEEP]" aligned to the token's timestamps within +/- 100 ms (0 leaks) And for allow, profane tokens appear verbatim (0 accidental masking/bleeping)
Formatting and Timing Integrity Compliance
Given persona formatting targets cplMax and wpmTarget and a diarized transcript When captions are segmented and line-broken Then >= 95% of lines have charactersPerLine <= cplMax; 0 lines exceed 1.1x cplMax And per-speaker reading speed is within wpmTarget +/- 10% for >= 95% of caption windows And no caption line spans across two different speaker labels (0 occurrences) And 99% of word timestamps differ from raw ASR timestamps by <= +/- 100 ms after post-processing
Multilingual Glossaries and Fallback to Generic
Given a multilingual recording with segments in languages {L1, L2} and persona glossaries for those languages When captions are generated with automatic language detection Then >= 98% of segments apply the glossary matching the detected language And if a persona-language caption profile is unavailable, the system falls back to the generic caption pipeline within 200 ms of detection without job failure And a PROFILE_FALLBACK warning event is recorded with personaId, language, and timestamp
Quality Metrics Collection and Automated Regression Gates
Given CI/CD execution on main and a fixed persona test suite When the regression job runs Then build passes only if WER <= baselineWER + 0.5 absolute, formatting compliance (cpl/wpm rules) >= 95%, acronym rule compliance >= 99%, and glossary term recall >= 95% with precision >= 98% And metrics are stored with buildId, commitSha, personaId, and timestamp and exposed via the metrics API And a failing gate blocks deployment (build status=failed)
Persona-Specific Highlight Heuristics
"As a sales rep, I want highlight suggestions that prioritize objections and next steps so that my clips capture the most actionable moments."
Description

Defines and applies persona-tuned scoring models for highlight detection, weighting signals such as keyword density, topic transitions, sentiment peaks, question/answer segments, objections and next steps (Sales), definitions and summaries (Educator), or insights and citations (Research). Consumes transcripts, speaker roles, and timing to propose clips within persona target runtimes. Produces confidence scores, reasons, and adjustable thresholds. Supports backfill recomputation when a persona changes and exposes evaluation dashboards to compare acceptance rates by persona.

Acceptance Criteria
Sales Persona: Objection and Next-Step Prioritization
Given a transcript with speaker roles labeled and at least two explicit customer objections and one stated next step When the persona is set to Sales and highlights are generated with default threshold Then at least 2 of the top 5 proposed clips include reasons that reference "objection" or "next step" and link to the corresponding transcript timestamps And each such clip duration is within the Sales persona's configured target runtime ±10% And each proposed clip includes a confidence score in [0.00, 1.00] with two-decimal precision and a sorted order by descending confidence And at least one selected clip’s start time is within 5 seconds of the highest negative sentiment peak in the session
Educator Persona: Definitions and Summaries Emphasis
Given a transcript containing at least one definition statement and one summary recap and speaker roles labeled Instructor and Student When the persona is set to Educator and highlights are generated Then at least 2 of the top 5 clips overlap by ≥5 seconds with the definition or summary segments And the reasons include the signals "definition" or "summary" and cite the matching transcript lines And each clip duration is within the Educator persona's configured target runtime ±10% And no clip contains more than 5 seconds of silence based on transcript timing gaps
Research Persona: Insights and Citation Detection
Given a transcript containing at least two statements that cite a study or paper and one novel insight statement When the persona is set to Research and highlights are generated Then at least 2 of the top 5 clips include reasons that reference "citation" or "insight" and extract the cited source phrase And each proposed clip includes the speaker role of the cited statement in the reasons And each clip duration is within the Research persona's configured target runtime ±10% And confidence scores for clips containing citations are on average ≥ 0.65
Persona Target Runtime and Safe Margins Enforcement
Given any selected persona with configured clip runtime range and safe pre/post-roll margins When highlights are generated Then 100% of proposed clips have durations within the persona's configured runtime range or within ±5% if near file boundaries And pre-roll and post-roll margins are applied without exceeding media bounds and are reflected in clip start/end timestamps And all timestamps are frame-accurate within ±100 ms of the source media And no proposed clip overlaps another by more than the configured overlap tolerance
Threshold Adjustment and Deterministic Results
Given a project and persona with a configurable highlight score threshold When highlights are generated at threshold 0.4 and then at threshold 0.6 on the same inputs Then the number of proposed clips at 0.6 is less than or equal to the number at 0.4 And every clip proposed at threshold 0.6 also appears in the set proposed at threshold 0.4 with identical boundaries And repeating generation at the same threshold produces identical clip boundaries and confidence scores within ±0.01 And the selected threshold value persists per persona for the project and across sessions
Persona Change Backfill Recompute
Given a processed project initially generated with the Sales persona When the persona is changed to Educator and backfill recomputation is triggered Then a recomputation job is enqueued within 5 seconds and visible in job status And previous proposed clips are archived and replaced by the new Educator proposals within the same project And for a 60-minute video, recomputation completes in under 10 minutes on standard infrastructure And an audit log entry records the persona change, user, timestamp, and counts of clips before/after
Evaluation Dashboard: Acceptance Rates by Persona
Given highlight proposals and user accept/reject actions recorded across personas over the last 30 days When the evaluation dashboard is opened with a date range filter applied Then acceptance rate is displayed per persona using the formula accepted/(accepted+rejected) with the sample size shown And the dashboard loads in under 2 seconds for 10k proposals and supports sorting by acceptance rate And a comparison view displays deltas between personas and flags any persona with acceptance rate below a configurable threshold And exporting the dashboard data as CSV preserves persona, date range, acceptance rate, and sample size columns
Apply, Preview, and Revert Defaults
"As a power user, I want to preview and undo persona changes so that I can experiment without risking my custom setup."
Description

Adds a Fastlane workflow that previews the delta between current project settings and the selected persona, applies changes atomically, and supports single-click undo/redo. Preserves user overrides by honoring field-level locks and records a change history for auditability. Provides idempotent operations to prevent double application and guards against conflicts with in-progress renders. Exposes an API to programmatically apply or revert persona bundles for batch operations.

Acceptance Criteria
Preview Delta of Persona vs. Current Project Settings
Given a project with existing settings and a selected persona When the user opens the Fastlane preview Then the UI displays a diff of all impacted fields showing current value -> persona value And fields with active locks are marked "Locked" and excluded from the pending change set And the preview shows counts for total evaluated, to-change, locked, and unchanged fields And the "Apply" action is disabled when to-change count is 0, enabled otherwise And the preview renders within 2 seconds for projects with up to 200 configurable fields
Atomic Apply Honors Field-Level Locks
Given a valid preview with at least one change and the user clicks Apply When the persona bundle is applied Then eligible fields are updated in a single atomic transaction (all-or-nothing) And locked fields remain unchanged And the UI confirms success with the exact number of fields updated matching the preview And on any error, no settings are changed, an error is shown, and the user can retry And the apply completes within 3 seconds under normal load
Single-Click Undo and Redo Restore Exact Prior State
Given a completed apply operation When the user clicks Undo Then all changes from that apply are reverted atomically and prior values are restored And the UI confirms success and updates the undo/redo stack When the user then clicks Redo Then the same changes are reapplied atomically And the undo/redo stack persists across sessions for the last 20 operations within 7 days
Change History Captures Complete, Immutable Audit Trail
Given any apply, undo, or redo completes When the user opens Change History Then a new immutable entry exists recording: timestamp (UTC), actor, project ID, persona ID and version, operation type, request ID, success/failure, and per-field diffs (field name, old value hash, new value hash, lock status) And entries are filterable by date, actor, operation, and persona And the user can export an entry to JSON or CSV
Idempotent Apply/Revert Prevents Duplicate Side Effects
Given an API or UI client submits an apply or revert with an Idempotency-Key and identical payload When the same request is received multiple times within 24 hours Then only one operation is executed and subsequent requests return the original result with no additional side effects or history entries And reapplying a persona when no differences exist returns 200 with "0 fields updated" and records a no-op entry in history
Apply is Blocked When Renders Are In Progress
Given one or more renders are in progress on the project When the user attempts to apply persona changes Then the system blocks the operation with HTTP 409 (API) or a conflict message (UI) listing affected render IDs and types And no settings are changed and the preview remains unchanged until renders complete
Programmatic Apply/Revert API with Batch Support
Given a valid OAuth2 token and a request to apply or revert a persona bundle When the client calls the API with projectId(s), personaBundleId, fieldLocks, and Idempotency-Key Then the API returns 200 with per-item results: operationId, fieldsUpdated, fieldsLocked, fieldsUnchanged, startedAt, completedAt And batch requests support up to 100 projects per call and return per-item statuses, using 207 Multi-Status when any item fails And unauthorized calls receive 401/403, invalid input 400, conflicts 409, and server errors 5xx And P95 latency is <= 3 seconds for batches up to 50 projects
Export Presets and Safe Margin Profiles
"As a creator, I want export presets that fit my persona’s target platforms so that my clips look correct without manual tweaking."
Description

Ships persona-aligned export presets covering aspect ratios, caption burn-in styles, audio normalization, and safe margins for common platforms (YouTube, Shorts/Reels, LMS players, podcast video). Ensures captions and lower-thirds remain within safe areas across resolutions and includes platform-specific bitrates, codecs, and file naming conventions. Integrates with the export pipeline to auto-select the best preset for the chosen persona while allowing manual override and saving as a custom preset. Validates outputs via automated checks for margin violations and loudness targets.

Acceptance Criteria
Persona-Based Auto-Selection in Export Dialog
Given a project with Persona SnapStart set to Podcaster, When the user opens the Export dialog for the first time, Then the preset "Podcast Video 1080p" is preselected with aspect ratio 16:9, captions style = burn-in with background, loudness target = -16 LUFS (stereo), and safe margin profile = Broadcast 5/8. Given a project with Persona SnapStart set to Educator, When the user opens the Export dialog for the first time, Then the preset "LMS Player 1080p" is preselected with aspect ratio 16:9, captions packaging = sidecar .vtt, loudness target = -16 LUFS, and safe margin profile = LMS 5/5. Given a project with Persona SnapStart set to Sales, When the user opens the Export dialog for the first time, Then the preset "Shorts/Reels 9:16" is preselected with aspect ratio 9:16, captions style = burn-in, loudness target = -14 LUFS, and safe margin profile = Vertical 5/10. Given a project with Persona SnapStart set to Research, When the user opens the Export dialog for the first time, Then the preset "YouTube 1080p" is preselected with aspect ratio 16:9, captions packaging = sidecar .srt, loudness target = -14 LUFS, and safe margin profile = YouTube 5/5. Given the user changes the preselected preset, When the Export dialog is reopened within the same session, Then the manually chosen preset remains selected unless the user sets a new default.
Cross-Resolution Safe Margin Validation for Captions and Lower-Thirds
Given any export with burned-in captions or lower-thirds enabled, When validation runs at 1280x720, 1920x1080, 3840x2160, and 1080x1920, Then 0 caption or lower-third glyph bounding boxes extend beyond the preset's safe area (>=5% inset left/right, >=5% top, >=8% bottom for captions; >=5% all sides for lower-thirds). Given a safe-margin violation is detected at any tested resolution, When validation completes, Then the export is marked Validation Failed and the report lists timestamp(s), layer name(s), and pixel coordinates of the violation(s). Given no violations are detected, When validation completes, Then the export is marked Validation Passed for safe margins and the report records the resolutions audited and sample counts.
Platform Codec/Bitrate/Resolution Compliance
Given the preset "YouTube 1080p" is selected, When the export completes and metadata is analyzed, Then video codec = H.264 High@4.2, resolution = 1920x1080 (SAR 1:1), fps = source (<=60), average video bitrate >= 12 Mbps, audio = AAC-LC 48 kHz 320 kbps, container = .mp4, and a sidecar .srt file exists. Given the preset "Shorts/Reels 9:16" is selected, When the export completes and metadata is analyzed, Then video codec = H.264 High@4.2, resolution = 1080x1920 (SAR 1:1), fps = source (<=60), average video bitrate >= 10 Mbps, audio = AAC-LC 48 kHz 256 kbps, container = .mp4, and captions are burned-in (no sidecar produced). Given the preset "LMS Player 1080p" is selected, When the export completes and metadata is analyzed, Then video codec = H.264 Main@4.0 or higher, resolution = 1920x1080, average video bitrate between 8 and 10 Mbps inclusive, audio = AAC-LC 48 kHz 192 kbps, container = .mp4, and a sidecar .vtt file exists. Given the preset "Podcast Video 1080p" is selected, When the export completes and metadata is analyzed, Then video codec = H.264 High@4.2, resolution = 1920x1080, average video bitrate between 10 and 12 Mbps inclusive, audio = AAC-LC 48 kHz 256–320 kbps, container = .mp4, and captions setting matches the preset (burn-in on or off).
Caption Packaging Consistency by Preset
Given a preset that specifies sidecar captions, When the export completes, Then the video contains no burned-in caption glyphs and a sidecar file exists with the specified format (.srt or .vtt) and identical base filename. Given a preset that specifies burned-in captions, When the export completes, Then captions are visually present in the video and no sidecar caption file is generated unless explicitly enabled by the user. Given any preset with captions enabled, When the exported caption file or burn-in is inspected, Then timestamps align within ±200 ms of the source transcript segments and no segment has overlapping timecodes.
Audio Loudness Normalization Validation
Given any export preset, When the exported audio is measured using ITU-R BS.1770-4, Then integrated loudness is within ±1.0 LU of the preset's target (-16 LUFS for Podcast Video and LMS; -14 LUFS for YouTube and Shorts/Reels), and LRA <= 12 LU. Given any export preset, When true-peak is measured, Then true-peak <= -1.0 dBTP. Given integrated loudness or true-peak is out of tolerance, When validation completes, Then the export is marked Validation Failed for audio with measured values recorded in the report.
Manual Override and Custom Preset Lifecycle
Given a system preset is modified in the Export dialog, When the user selects Save as Custom Preset and provides a unique name, Then a new custom preset is created, persisted to the user's account, and appears under Custom Presets. Given a custom preset is selected, When an export is performed, Then the export log records presetId, presetName, persona, and all non-default parameter overrides. Given a custom preset is set as default for a persona, When the Export dialog is opened for projects with that persona, Then the custom preset is preselected. Given a custom preset is deleted, When the user confirms deletion, Then it is removed from the list and no longer applied as a default for any persona.
File Naming Convention Enforcement
Given any export preset, When files are written, Then the primary file name matches {projectTitle}_{persona}_{platform}_{resolution}_{YYYYMMDD}_{seq}.{ext} with spaces replaced by underscores, non-ASCII characters removed, and seq starting at 01 and incrementing to avoid collisions. Given sidecar captions are produced, When files are written, Then caption files share the primary base name and use the extension specified by the preset (.srt or .vtt). Given a custom preset defines a custom naming pattern, When exporting, Then output files follow the custom pattern and a sample filename preview is shown prior to export.

Smart Trim

Auto-removes dead air, stumbles, and long pauses from the generated clips while protecting meaning and rhythm. A simple ‘gentle/standard/aggressive’ slider keeps control in your hands and delivers polished cuts with no manual editing.

Requirements

Trim Intensity Control Slider
"As a creator, I want to quickly choose how aggressively Smart Trim edits my clip so that I can balance polish with natural pacing without manual tweaking."
Description

Provides a three-position slider (Gentle, Standard, Aggressive) that maps to tunable thresholds for silence duration, disfluency removal, and gap smoothing. Includes an advanced panel for fine-grained parameters (min/max pause length, SNR threshold, disfluency types to target, crossfade duration). Preserves per-project defaults and allows per-clip overrides. Exposes keyboard shortcuts and accessible labels. Changes update the preview instantly and persist in exported presets.

Acceptance Criteria
Three-Position Slider Maps to Preset Thresholds
Given a project with defined parameter presets for Gentle, Standard, and Aggressive And a clip is open in the editor When the user selects Gentle, Standard, or Aggressive on the Trim Intensity slider Then the engine applies exactly the parameter set stored for the selected position to the active clip (silence thresholds, disfluency targets, gap smoothing) And the slider’s selected label matches the applied preset name And the advanced panel displays the applied values for the selected position And the selection persists after saving and reopening the project
Advanced Panel Parameter Editing and Validation
Given the advanced panel is opened for the active clip When the user edits Min Pause Length Then the value is constrained to 0.1–10.0 seconds with 0.1 s precision and displayed in seconds When the user edits Max Pause Length Then the value is constrained to 0.2–20.0 seconds and must be ≥ Min Pause Length When the user edits SNR Threshold Then the value is constrained to 0–60 dB with 1 dB precision When the user edits Crossfade Duration Then the value is constrained to 0–300 ms with 5 ms precision When the user toggles Disfluency Types Then the options include fillers, repetitions, false starts, and mid-word stutters and reflect their on/off state And invalid inputs are blocked with inline error messaging and do not update the underlying parameters And changes apply immediately to the active clip without altering the project default unless saved as a preset
Instant Preview Reflects Trim Intensity Changes
Given the clip is loaded in the preview player When the user adjusts the Trim Intensity slider or any advanced parameter Then visual cut markers and waveform regions update within 300 ms And playback reflects the new trims within 1,000 ms And cut boundaries are smoothed using the configured crossfade duration (no audible clicks) And the UI remains responsive during updates (frame rate ≥ 50 FPS)
Per-Project Default Trim Intensity Persistence
Given Project Settings define a default Trim Intensity and its parameter set When a new clip is created or imported into the project Then the clip inherits the project’s default intensity position and parameters And after closing and reopening the project, the default remains unchanged and is applied to subsequent new clips And modifying a clip’s parameters does not change the project default
Per-Clip Overrides with Reset to Default
Given a clip that initially inherits the project default When the user changes the intensity position or any advanced parameter for that clip Then the clip is marked as Overridden and the current settings are applied only to that clip And a Reset to Project Default action restores the clip to the project default parameter set for the current intensity And other clips in the project remain unchanged
Keyboard Shortcuts and Accessibility Compliance
Given the editor has focus When the user presses Ctrl/Cmd+1, Ctrl/Cmd+2, or Ctrl/Cmd+3 Then the Trim Intensity changes to Gentle, Standard, or Aggressive respectively and the change is announced to screen readers And when the slider has focus, Left/Right Arrow moves one step between positions And Alt/Option+A toggles the Advanced panel visibility And all controls expose accessible names, roles, states, and values via ARIA And the slider and advanced controls are fully operable by keyboard only and meet WCAG 2.1 AA criteria 2.1.1 (Keyboard) and 4.1.2 (Name, Role, Value)
Exported Presets Persist Trim Parameters
Given a clip with an active intensity position and customized parameters When the user exports a Trim preset Then the exported preset includes the intensity position and the exact parameter values (pause lengths, SNR threshold, disfluency targets, crossfade duration) And when the preset is imported into another project and applied Then the same values are restored and selecting that intensity yields identical trim behavior on the same source media And preset export/import succeeds across machines and app restarts
Silence and Stumble Detection Engine
"As an educator or podcaster, I want the system to automatically detect dead air, stumbles, and long pauses so that I don’t have to scrub and cut them manually."
Description

Implements a hybrid detection pipeline combining voice activity detection, ASR transcripts, and disfluency models to locate dead air, long pauses, filler words, false starts, and repeated phrases. Supports multi-speaker and multi-track inputs with channel isolation to avoid cutting over active speakers. Assigns confidence scores to each candidate cut and respects user-defined thresholds per intensity level. Guards against false positives by classifying non-speech audio (applause, music beds) and by honoring minimum segment duration.

Acceptance Criteria
Trim long silences based on intensity thresholds
Given an audio track containing known pauses of 0.3s, 0.6s, and 1.2s and Gentle level with silence_threshold=0.8s, When the detection engine runs, Then only pauses >= 0.8s are marked and removed, and shorter pauses are retained. Given the same track and Standard level with silence_threshold=0.5s, When the engine runs, Then pauses >= 0.5s are removed and shorter pauses are retained. Given the same track and Aggressive level with silence_threshold=0.25s, When the engine runs, Then all three pauses are removed. Rule: No single cut is shorter than 100 ms. Rule: Cut boundary timestamp error is <= ±80 ms versus ground truth.
Disfluency and false-start trimming with semantic safeguards
Given a transcript with fillers ("um", "uh"), repeated phrases within 2s, and false starts, When disfluency removal is enabled, Then corresponding audio is removed and word boundaries are preserved in captions. Rule: Precision >= 0.90 and recall >= 0.85 for disfluency removal on a 200-utterance labeled test set. Rule: Lexical "like" (verb/adjective) and proper nouns are preserved in >= 95% of cases as measured by the same set. Rule: No cut occurs within 150 ms of a speaker-change boundary.
Multi-speaker and multi-track channel isolation
Given two speakers on separate tracks where one is silent while the other speaks, When the engine runs, Then no cut overlaps any interval where any track has VAD confidence >= 0.7. Given overlapping speech across speakers, When the engine runs, Then no removal occurs within the overlap window. Rule: Per-track cuts are applied only where all tracks are silent. Rule: Mixed export contains no truncation of active speaker audio.
Non-speech audio classification guards against false positives
Given continuous music bed segments and applause segments labeled by the classifier with confidence >= 0.8 and no speech present, When the engine runs, Then these segments are not removed by silence trimming. Rule: Non-speech classifier false positive rate <= 5% and false negative rate <= 10% on the non-speech validation set of at least 30 minutes of audio. Rule: Short SFX bursts < 300 ms are never treated as silence.
Minimum segment duration and cut merging
Given candidate cuts that produce segments shorter than minimum_segment_duration (default 1.0s), When the finalize step runs, Then adjacent segments are merged until the minimum is satisfied. Rule: Any two cuts separated by < 250 ms are merged into a single cut. Rule: No resulting segment in the output is shorter than the configured minimum. Rule: Total clip duration deviation from original minus removed content is <= 0.5%.
Confidence scoring and per-intensity thresholds
Given candidate cuts with confidence scores in [0,1] and thresholds Gentle=0.75, Standard=0.60, Aggressive=0.45, When the user switches levels, Then only candidates with confidence >= the selected level threshold are applied. Rule: Thresholds are user-configurable and persisted per project. Rule: Timeline visualization and cut count update within 500 ms of threshold or level change. Rule: Export uses the currently filtered set of candidates.
Rhythm-Preserving Cut Rules
"As a viewer-focused editor, I want trims that respect speech rhythm and sentence boundaries so that the result feels natural and maintains meaning."
Description

Applies prosody-aware constraints to avoid choppy results: align cuts to word and sentence boundaries; enforce minimum inter-sentence pause; limit consecutive cuts within a rolling window; and apply short crossfades or time-stretch up to a safe limit to smooth transitions. Adds an adjustable context cushion before and after each cut to preserve meaning. Maintains A/V sync and prevents mid-phoneme truncation. Provides language-specific heuristics for common disfluencies.

Acceptance Criteria
Cut Alignment to Linguistic Boundaries
- All audio cut points align to ASR-derived word boundaries with absolute tolerance ≤ 20 ms. - No cut occurs within a word; 0 instances of mid-phoneme truncation verified by phoneme-level forced alignment (tolerance ≤ 15 ms). - Sentence-level cuts only at detected sentence boundaries (punctuation or ≥ 300 ms pause); ≥ 99% of sentence cuts within 20 ms of boundary on validation set. - If no clean boundary exists within ±150 ms of a proposed cut, the cut is shifted to the nearest valid boundary or canceled.
Minimum Inter-Sentence Pause Preservation
- After trimming, maintain a configurable minimum pause between sentences: gentle=250 ms, standard=200 ms, aggressive=150 ms (user override 150–400 ms). - No resulting inter-sentence pause is shorter than the configured minimum by more than 10 ms. - Overlong pauses (>1200 ms) adjacent to cuts are reduced to ≤ 400 ms (≤ 600 ms in gentle) without violating boundary alignment. - Verification on processed output shows ≥ 99% of inter-sentence pauses meet configured minimum.
Consecutive Cuts Limit within Rolling Window
- In any rolling 10-second window, number of cuts does not exceed: gentle=1, standard=2, aggressive=4. - If the limit would be exceeded, adjacent cuts are merged or context cushions expanded to reduce count while preserving alignment and pause rules. - Post-process audit reports 0 windows exceeding the configured limit across the entire timeline.
Smoothing via Crossfade and Time-Stretch
- Apply crossfade at each cut between 40–120 ms unless separated by detected silence ≥ 300 ms (then crossfade disabled). - Local time-stretch used for rhythm smoothing is limited to |rate change| ≤ 3% over ≤ 300 ms; measured pitch deviation ≤ 5 cents. - No transient clicks/pops > -36 dBFS peak within ±50 ms of any cut; RMS discontinuity across the crossfade ≤ 6 dB. - Perceptual check metric (e.g., no silence insertion artifacts > 150 ms) shows 0 violations on validation set.
Context Cushion Around Cuts
- Add context cushion before and after each cut: gentle=500 ms, standard=300 ms, aggressive=150 ms (user override 100–1000 ms). - Cushions never truncate the first or last full word adjacent to the cut; at least one non-filler content word is retained on each side when available. - When constraints conflict (e.g., rolling-window limit), cushions may shrink in 50 ms steps but never below 100 ms total per side. - ≥ 99% of cuts include cushions within ±20 ms of the configured values.
A/V Sync Integrity After Trimming
- Audio-video sync drift after all edits is ≤ 40 ms at any sampled timestamp compared to source alignment. - Video edits occur at frame boundaries; audio is compensated to maintain sync without dropping or duplicating frames. - Output container timebase and timestamps validate with no errors; playback in two reference players shows 0 detectable lip-sync issues in QA spot checks (n≥5, 2-minute segments).
Language-Specific Disfluency Handling
- Apply disfluency heuristics per language (e.g., EN: um/uh/er/hmm/you know/like[discourse]; ES: eh/em/este/o sea) with POS/context gating to avoid lexical removals. - On a labeled validation set, filler-removal precision ≥ 0.90 and recall ≥ 0.80; false positive rate for lexical "like"/"este" ≤ 10%. - Disfluency removals respect boundary alignment, pause minimums, and smoothing limits with 0 rule violations detected by automated audits.
Real-time Preview and A/B Compare
"As a user, I want to audition Smart Trim changes before applying them so that I can trust the output and fine-tune if needed."
Description

Displays proposed cuts as timeline markers with before/after waveforms and caption overlays. Provides a one-click A/B toggle, per-cut enable/disable checkboxes, and scrubbable preview with instant re-render at low resolution. Shows estimated duration saved and a diff list of removed segments with timestamps. Keyboard controls allow quick auditioning and reverting of individual cuts during review.

Acceptance Criteria
Markers, Waveforms, and Caption Overlays Render for Proposed Cuts
Given a video with at least 5 proposed cuts and generated captions When the review screen loads Then timeline markers appear at each proposed cut start and end with timestamps visible on hover And before/after waveforms are displayed and aligned to the same time scale And caption overlays are shown and time-synced within ±80 ms of audio And selecting a cut marker moves the playhead to the cut start within ±200 ms
One-Click A/B Toggle Maintains Context
Given playback is paused or playing at time t When the user clicks the A/B toggle once Then the mode switches between Original (A) and Trimmed (B) And the playhead timecode stays at t ±40 ms And waveforms and captions update to the selected mode within 300 ms And a visible label indicates the current mode
Per-Cut Enable/Disable Updates Preview and Metrics
Given a list of proposed cuts each with an enable/disable checkbox When the user toggles one or more checkboxes Then the trimmed preview excludes disabled cuts and includes enabled cuts And Estimated Duration Saved recalculates within 300 ms And the diff list updates to include only enabled removed segments And disabled cuts appear visually distinct from enabled cuts
Scrubbable Low-Resolution Preview Re-renders Instantly
Given low-resolution preview is active When the user scrubs or seeks to a new position Then audio/video respond with seek latency ≤120 ms (P95) and remain A/V synced within ±80 ms And after a cut is enabled/disabled, the trimmed preview re-renders within 500 ms (P95)
Estimated Savings and Diff List Accuracy and Interactivity
Given at least one enabled cut When the system computes totals Then Estimated Duration Saved equals the sum of enabled cut durations within ±0.1 s And the diff list shows each removed segment with start and end in HH:MM:SS.mmm And clicking a diff item moves the playhead to 1.0 s before the segment start in Original (A) mode
Keyboard Controls for Auditioning and Reverting Individual Cuts
Given the review screen has focus When the user presses keyboard shortcuts for A/B toggle, play/pause, next cut, previous cut, enable/disable current cut, and revert current cut Then the corresponding action executes within 150 ms And UI state (mode label, checkbox, playhead) reflects the change immediately And a keyboard shortcuts overlay opens with '?' and lists all available shortcuts
Caption and Timestamp Reflow
"As a knowledge worker, I want captions and timestamps to stay accurate after trimming so that summaries and highlights remain reliable and shareable."
Description

Re-times and regenerates captions and transcript segments to match the trimmed media while preserving speaker labels. Updates all derived artifacts—summaries, highlight clip ranges, share links, and exports (SRT/VTT/EDL/XML)—to reflect new timecodes. Prevents orphaned or overlapping caption frames by snapping to word boundaries and rewrapping lines. Provides a validation pass that flags any inconsistent timestamps before export.

Acceptance Criteria
Reflow Captions After Smart Trim
Given a word-level aligned transcript and Smart Trim has removed one or more time ranges When caption and timestamp reflow is executed Then every caption’s start and end time snaps exactly to the start or end of a kept word token And no caption start or end time lies outside [0, new_media_duration] And no caption spans across a removed (trimmed) time range; affected captions are split or removed accordingly And the chronological order of captions matches the order of words in the kept audio And the concatenated caption text equals the sequence of kept words, with no dropped or duplicated words
Speaker Labels Preservation Post-Trim
Given speaker-labeled utterances exist in the transcript When reflow is performed after Smart Trim Then each caption retains the speaker label of its source utterance And speaker label changes occur only at real speaker change boundaries present in the kept audio And if an utterance is split by a trim, all resulting captions from that utterance retain the same original speaker label And no caption has an “Unknown” or empty speaker label if the source utterance was labeled
Derived Artifacts Timecode Update
Given summaries, highlight clip ranges, share links, and exportable artifacts exist prior to trimming When reflow completes Then all highlight clip start/end times are re-indexed to the new timeline and lie within [0, new_media_duration] And any summary references with timestamps are updated to the new offsets And share links containing time parameters are rewritten to the updated timecodes or, if fully trimmed out, snap to the nearest next valid word boundary And regenerated SRT/VTT/EDL/XML artifacts reflect the updated caption times with no stale (pre-trim) references And no derived artifact references a timecode that no longer exists in the trimmed media
No Orphaned or Overlapping Caption Frames
Given reflowed captions are available When validating caption intervals Then no caption has zero or negative duration (end > start) And no two captions overlap (each caption’s start >= previous caption’s end) And no caption is empty or contains only whitespace And caption boundaries align to word boundaries (starts at a word start; ends at a word end) And line wrapping occurs at word boundaries with no broken words and no leading/trailing whitespace per line
Pre-Export Timestamp Validation
Given a project has been reflowed after Smart Trim When the pre-export validation pass is executed Then any issue (overlap, out-of-bounds, unsnapped boundary, misordered timestamps, empty caption, missing speaker label) is listed with type, count, and affected time ranges And export is blocked if one or more issues are present, with a clear error status and actionable messages And export proceeds only when zero issues are reported, returning a “Valid” status
Cross-Format Export Fidelity
Given reflowed captions are ready for export When exporting to SRT, VTT, EDL, and XML Then SRT/VTT caption start and end times match the internal model to millisecond precision And EDL/XML times match to within ±1 frame at the project frame rate And speaker labels are preserved in formats that support them (e.g., XML) and omitted gracefully where not supported (e.g., SRT/VTT) And importing the EDL into a supported NLE reproduces cut points at the updated timecodes within ±1 frame
Batch Apply and Undo-safe Workflow
"As a busy producer, I want to apply Smart Trim across multiple clips with an easy way to undo changes so that I can move fast without risk."
Description

Enables applying Smart Trim settings to a single clip, a selection, or all generated clips with queue-based processing and progress feedback. Operates non-destructively by preserving originals, storing cut lists as metadata, and supporting full undo/redo plus per-cut revert. Supports project-level defaults and preset sharing across teams. Logs changes for auditability and allows restoring factory settings in one step.

Acceptance Criteria
Apply Smart Trim to a single clip with progress
Given a project with at least one generated clip and a selected Smart Trim intensity (gentle|standard|aggressive) When the user applies Smart Trim to a single clip Then a job for that clip is enqueued and a visible progress indicator (0–100%) appears and updates at least every 2 seconds or on state change And on completion the clip preview reflects the applied cuts And the original media remains unchanged And a cut list (timecode in/out pairs) and the applied settings are stored in the clip's metadata And if the job fails, the status shows Failed with an error message and no metadata changes are committed
Batch apply to a selected set of clips
Given multiple generated clips are selected and a Smart Trim preset/slider value is chosen When the user clicks Apply Smart Trim Then N jobs (one per selected clip) are added to the processing queue in the order they appear in the UI And each selected clip displays an individual state (Queued|In Progress|Completed|Failed) And the same preset/slider value is applied consistently to all selected clips And the UI shows overall batch progress (e.g., 3/10 completed) and does not block other navigation And reordering or changing the current selection does not alter the order of already enqueued jobs
Apply to all generated clips with queue control
Given a project containing generated clips and an Apply to All action When the user triggers Apply to All Then all eligible clips are enqueued for Smart Trim And the user can pause the queue; within 2 seconds no new job begins processing while paused And the user can resume the queue; processing continues from the next queued job And the user can cancel pending jobs; canceled jobs are removed from the queue without modifying clip metadata And the user can abort an in-progress job; the clip remains unchanged and the job ends within 3 seconds And an ETA is displayed and stabilizes to within ±20% accuracy after the first 3 jobs complete
Undo and redo a batch apply operation
Given a completed batch Smart Trim apply affecting M clips When the user selects Undo Then each affected clip reverts to its prior state by removing the associated cut list and settings while leaving original media unchanged And the history shows a single atomic undo step labeled with the action and scope (e.g., Smart Trim applied to M clips) When the user selects Redo Then the same cut lists and settings are reapplied deterministically to the same set of clips, yielding the same results And both undo and redo operations complete without leaving partial states if interrupted
Per-cut revert within a trimmed clip
Given a clip that has a Smart Trim cut list with one or more cuts When the user selects a specific cut and chooses Revert Cut Then the corresponding timecode pair is removed from the cut list And playback includes the restored segment seamlessly with no new artifacts added by the system And the action is captured as an undoable step; Undo restores the cut and Redo removes it again And reverting all cuts on a clip restores the clip to an untrimmed state while preserving the clip's metadata history
Project defaults and team preset sharing
Given project-level Smart Trim defaults (intensity and options) are configured When new clips are generated or imported into the project Then those clips inherit the project default Smart Trim settings unless explicitly overridden per apply action When a user saves the current settings as a named preset Then the preset is stored with a unique ID and version When the preset is shared to a team workspace Then other team members can discover and apply it, and only users with edit permission can modify or delete it And importing/exporting presets uses a JSON package with validation; invalid or incompatible presets are rejected with a clear error And changing the project default affects only future applies and does not retroactively change previously trimmed clips
Change logging and factory reset behavior
Given audit logging is enabled When any Smart Trim action occurs (apply, undo, redo, per-cut revert, preset create/edit/share, default change, queue pause/resume/cancel/abort) Then an audit record is written with timestamp, actor, project ID, clip IDs affected, previous settings, new settings, job result, and correlation ID And logs are queryable by project, clip, actor, action type, and date range, and exportable as CSV and JSON When the user selects Restore Factory Settings and confirms Then project-level defaults revert to product defaults, the processing queue is cleared, and local presets are archived and disabled (not deleted) And existing clips and all audit logs remain intact and unchanged And a confirmation dialog summarizes the impact and requires explicit confirmation before proceeding

One-Tap Share

Publish your first clips with a single click. Fastlane creates a clean share page and pre-fills titles and descriptions. Copy a ready-made blurb for email or social and get a trackable link instantly—momentum, not menus.

Requirements

Instant Share Page Generation
"As a creator repurposing a recording, I want an instant share page for my clip so that I can publish a polished destination without manual page setup."
Description

Automatically generate a fast, responsive share page for any selected clip with an embedded player, captions, and a transcript excerpt. The page should include pre-filled title and description, Open Graph/Twitter Card metadata for rich previews, and optional thumbnail. It must be CDN-cached for global performance, mobile-friendly, and brandable with light/dark themes. Integrate with ClipSpark’s asset storage and caption tracks to ensure accessibility and accurate timestamps. Provide a unique, stable URL as soon as the clip is selected and refresh the preview in real time when metadata is edited. Support basic SEO (indexing toggle), a clear call-to-action, and optional download button, all configurable per clip.

Acceptance Criteria
Instant Stable URL Provision
- A unique HTTPS share URL is generated within 1 second of clip selection and displayed to the user. - The URL remains stable across edits to metadata, theme, or CTA; no new URL is minted on edits. - Visiting the URL returns HTTP 200 with no more than one redirect hop and enforces TLS 1.2+. - Canonical link tag matches the share URL; no conflicting canonical/og:url values. - The URL contains no PII and length is ≤ 200 characters.
Share Page Player, Captions, and Transcript Excerpt
- An embedded player loads the selected clip and is functional on Chrome, Safari, Firefox, Edge, iOS, and Android. - Captions auto-load from the clip’s caption track; caption timing drift is ≤ 250 ms at 10 sampled timestamps. - A transcript excerpt is rendered with time-synced lines; clicking a line seeks the player within 200 ms. - Player controls are keyboard-focusable with aria labels; page passes WCAG 2.1 AA for non-text contrast and focus visibility. - Playback starts within 1 second on a simulated 4G network; seeking works with byte-range requests.
Auto Metadata and Social Rich Preview
- Title and description are auto-populated from clip metadata; user edits persist and render on the share page within 2 seconds of save. - Open Graph and Twitter Card tags (og:title, og:description, og:url, og:type=video.other, twitter:card=summary_large_image) are present and correct. - Thumbnail uses the provided image or a generated frame fallback; served at 1200x630 in JPEG/PNG/WebP. - Facebook Sharing Debugger and Twitter Card Validator report no critical errors for the URL. - Edits to title/description/thumbnail trigger CDN purge; updated meta is served within 60 seconds globally.
CDN Caching and Global Performance
- Share page HTML, player manifests, thumbnails, and captions are served via CDN with cache HIT rate ≥ 90% after initial warmup. - Median TTFB ≤ 200 ms and LCP ≤ 2.5 s under simulated 4G for test nodes in US, EU, and APAC. - Cache invalidates automatically on metadata or asset updates; stale content window ≤ 60 seconds. - HTTP/2 or HTTP/3 is used for all assets; TLS certificates are valid and not expired. - Streaming starts within 1 second; byte-range and partial content (206) supported for video.
Mobile Responsiveness and Brand Themes
- Layout is responsive at 320, 375, 768, 1024, and 1440 px widths with no horizontal scrolling and minimum 16 px body text. - Light and dark themes are available per clip; Auto mode honors prefers-color-scheme. - Brandable logo and accent color configurable per clip; contrast meets WCAG AA for text and UI components. - Player maintains 16:9 aspect ratio; captions do not overlap controls on small screens. - Favicon and theme-color meta reflect the selected theme.
Real-time Preview Refresh During Metadata Edit
- In-app preview updates within 500 ms when title, description, thumbnail, CTA text, or theme is edited, without page reload. - Live share page reflects published changes within 60 seconds due to CDN purge; no broken styles during propagation. - The original share URL continues to resolve to the latest version; no additional URLs created. - Concurrent edits apply last-writer-wins without HTTP errors; final state matches the most recent save. - The preview pane shows updated Open Graph/Twitter meta preview placeholders matching current edits.
SEO Indexing Toggle, CTA, and Download Configuration
- When indexing is off, meta robots and X-Robots-Tag are set to noindex,nofollow; the URL is excluded from the sitemap while remaining publicly accessible. - When indexing is on, index,follow is set with a single canonical; no conflicting robots directives are present. - A clear CTA button is visible above the fold; label and target URL configurable per clip; keyboard and screen-reader accessible. - Optional Download button is configurable per clip; when enabled, file is served with correct MIME and Content-Disposition: attachment; when disabled, no direct file URL is exposed in markup. - All per-clip configurations persist to and are retrievable from the API.
One-Click Multi-Platform Publish
"As a podcaster, I want to send my clip to all my social channels with one tap so that I can publish quickly without juggling multiple apps."
Description

Enable users to publish a selected clip with a single action to multiple destinations (e.g., YouTube Shorts, TikTok, Instagram Reels, LinkedIn, X, and a generic webhook). Handle OAuth-based account linking, token refresh, and secure credential storage. Auto-apply platform-specific constraints (duration limits, aspect ratios, caption formats) and attach the prefilled title, description, hashtags, and thumbnail. Execute publishing via a background job queue with retries, exponential backoff, rate limiting, and idempotency keys. Provide real-time status updates, success/failure notifications, and deep links to the published posts. Offer "Share Now" and scheduling options with timezone support.

Acceptance Criteria
One-Click Multi-Platform Publish Queuing
Given the user has linked at least one destination account (YouTube Shorts, TikTok, Instagram Reels, LinkedIn, X, or a generic webhook) And the user has selected a single clip and at least one destination When the user clicks "Share Now" Then the system creates a single multi-destination publish job within 3 seconds And creates one child task per selected destination And displays a job identifier and per-destination status as Queued within 2 seconds And the clip, selected destinations, and metadata hash are stored with the job
OAuth Linking and Secure Token Handling
Given the user initiates account linking for a supported platform When the OAuth flow completes successfully Then the access and refresh tokens are stored encrypted at rest and are never shown in plaintext via UI or API And only minimal publish-related scopes are requested and stored And access tokens are auto-refreshed before expiry using the refresh token And if refresh fails or the token is revoked, the account is marked Reauth Required and subsequent publishes to that destination are blocked with a clear error prompting relink And a successful token refresh is logged with timestamp (without sensitive values)
Platform Constraints Adaptation and Caption Handling
Given the selected destinations have differing duration limits, aspect ratios, and caption format requirements When the user publishes the clip to multiple destinations Then the system auto-transcodes each rendition to the platform-required aspect ratio (e.g., 9:16 for Shorts/Reels/TikTok) using letterboxing/pillarboxing or smart crop as configured And clips exceeding a platform's maximum duration are auto-trimmed to that maximum with a short fade-out while preserving A/V sync and caption alignment And caption delivery matches platform requirements (burned-in for TikTok/Instagram Reels; sidecar .srt for YouTube Shorts; sidecar .srt or .vtt for LinkedIn; omitted if unsupported) And any destination that cannot be conformed is marked Skipped with a validation message and is not enqueued
Metadata Mapping, Hashtags, Thumbnail, and Webhook Payload
Given the clip has a prefilled title, description, hashtags, and a thumbnail When publishing to multiple destinations Then each platform's fields are populated according to its mapping and character limits, truncating gracefully without breaking words and appending an ellipsis if needed And hashtags are de-duplicated, normalized, and appended at the end if not already present And the thumbnail is applied where the platform API supports custom thumbnails; where not supported, the field is ignored and surfaced as N/A in the UI And the generic webhook receives an HTTPS POST with a JSON payload including clipId, videoUrl, thumbnailUrl, title, description, hashtags[], destinations[], and an idempotencyKey, with an HMAC-SHA256 signature header using a stored secret
Background Jobs: Retries, Backoff, Idempotency, and Rate Limiting
Given a publish child task encounters a transient error (network error, HTTP 5xx, or HTTP 429) When the task retries Then it retries up to 5 times with exponential backoff starting at 2 seconds and capping at 60 seconds, adding jitter, and honoring Retry-After when present And HTTP 4xx (except 429) are treated as permanent failures and do not retry And an idempotency key unique to clipId+destination+metadata hash ensures no duplicate posts across retries or re-submissions within 24 hours And all attempts are structured-logged with timestamps, attempt number, error codes, and correlation IDs And webhook deliveries follow the same retry and idempotency semantics, considering any 2xx as success
Real-Time Status Updates, Notifications, and Deep Links
Given a multi-destination publish job is queued or running When a destination task changes state Then the UI updates within 2 seconds via WebSocket/SSE to reflect Queued, Processing, Succeeded, Failed, Skipped, or Canceled And on success the destination row shows a deep link URL to the published post And on failure the destination row shows a human-readable error with the underlying code and a Retry action And the job summary aggregates per-destination states and emits a completion notification when all destinations reach a terminal state
Scheduling with Timezone Support and Share Now Override
Given the user selects Schedule and chooses a future date/time and timezone When the schedule is saved Then the system stores the UTC timestamp along with the original timezone And the job enqueues at the correct local time, including across daylight saving transitions And schedules in the past are blocked with a validation error And a scheduled publish can be edited or canceled until it enters Processing And selecting Share Now overrides the schedule and enqueues immediately
Auto Title & Description Prefill
"As an educator, I want auto-generated titles and descriptions so that I can publish faster while keeping messaging clear and consistent."
Description

Use AI to generate concise, context-rich titles and descriptions from the clip’s transcript, summary, and detected key moments. Conform to platform character limits and style guidelines, and optionally include suggested hashtags and mentions. Present editable fields with inline guidance and live previews for each destination. Maintain version history and allow quick revert. Ensure safe content by applying moderation filters and provide language selection for localization.

Acceptance Criteria
AI Prefills Title and Description from Clip Context
Given a user selects a clip with an available transcript, summary, and detected key moments When Auto Title & Description Prefill is triggered Then the generated title is 30–80 characters, concise, and references at least one primary topic from the clip And the generated description is 1–3 sentences summarizing the clip’s value and context And both fields are derived only from the clip’s transcript, summary, or detected key moments and contain no unrelated content And both fields contain no placeholder tokens (e.g., "lorem", "[title]")
Platform Character Limits and Style Guide Compliance
Given the user selects destinations (e.g., YouTube, X, LinkedIn, Instagram) When prefills are generated for each destination Then all generated fields respect platform character limits (YouTube title ≤ 100, YouTube description ≤ 5000, X text ≤ 280, LinkedIn post ≤ 3000, Instagram caption ≤ 2200) And titles use Title Case without ALL CAPS and avoid trailing punctuation; descriptions use sentence case And no field is auto-truncated mid-word; if a limit would be exceeded, the system shortens intelligently with an ellipsis and preserves semantic completeness
Optional Hashtags and Mentions Suggestions
Given the "Include hashtags and mentions" toggle is on When prefills are generated Then up to 3 hashtags and up to 2 mentions are suggested per destination based on named entities in the clip And suggestions are platform-aware (#, @) and included only if total length stays within that platform’s limit And turning the toggle off removes all hashtags and mentions from all destinations And the user can remove any individual suggestion with one click
Editable Fields with Inline Guidance and Live Preview
Given prefills are displayed When the user edits any title or description Then inline guidance shows live remaining character count, style tips, and platform-specific warnings And live preview for each destination updates within 200 ms of the last keystroke And the preview matches each platform’s truncation, line breaks, link rendering, and hashtag/mention formatting
Version History with Quick Revert
Given a user has edited prefilled fields at least once When the user makes an edit and clicks Save Then a new version snapshot is stored with timestamp and editor identity And the last 10 versions per clip per destination are retained and viewable And clicking Revert on any prior version instantly restores its content to the current fields without deleting other versions
Moderation Filtering of Unsafe Content
Given prefills have been generated When the content contains hate speech, adult content, self-harm encouragement, or PII as defined by the moderation policy Then the unsafe segments are blocked from publishing and highlighted to the user with reasons And the system provides a safe alternative rewrite for each flagged segment that preserves intent while removing violations And the user cannot publish until all flagged items are removed or replaced
Language Selection and Localization
Given the user selects a language for output When prefills are generated Then the title and description are produced in the selected language using locale-appropriate punctuation and spacing And right-to-left languages render correctly in edit fields and previews And if the selected language is unsupported, the system falls back to English and displays a non-blocking notice And hashtags are localized or transliterated to the selected language while maintaining platform formatting
Share-Optimized Blurb Generator
"As a knowledge worker, I want ready-made blurbs for different channels so that I can share my clip quickly with messaging that fits each audience."
Description

Produce short copy variants tailored for email, Slack, LinkedIn, and X that include a compelling hook, timestamped context, and a clear call-to-action. Allow tone presets (professional, friendly, punchy) and emoji/hashtag toggles. Generate multi-language variants and surface a one-click copy-to-clipboard action. Integrate brand voice preferences at the workspace level and enforce safety checks to avoid sensitive or off-brand content. Attach the trackable smart link and show estimated character counts where relevant.

Acceptance Criteria
Channel-Specific Blurb Generation
Given a processed video with transcript and highlights available And the user selects Email, Slack, LinkedIn, and X as target channels When the user clicks Generate Blurbs Then one variant per selected channel is produced within 5 seconds And each variant contains a compelling hook, a timestamped context reference, and a clear call-to-action And each variant includes the workspace's trackable smart link appended or hyperlinked to the timestamp reference And a channel-appropriate title and description are pre-filled where applicable And channel-specific estimated character counts are displayed and updated live And the system flags variants that exceed the configured character limits for their channel
Tone Presets and Emoji/Hashtag Toggles
Given the tone preset is set to Professional, Friendly, or Punchy And emoji and hashtag toggles are set On or Off When the user generates blurbs Then the wording of each variant reflects the selected tone as classified by the tone model with confidence ≥ 0.7 And when the emoji toggle is Off no emojis appear; when On at least one context-appropriate emoji appears where channel norms allow And when the hashtag toggle is Off no hashtags appear; when On 1–3 relevant hashtags appear for channels that support hashtags And a preview shows the applied tone and toggles per channel
Multi-Language Variant Generation
Given the user selects one or more languages in addition to the source language When generating blurbs Then a localized variant is produced for each selected language per channel And timestamps retain the original time format and remain aligned to the source media And the CTA text is localized while the smart link remains unchanged and attached And right-to-left languages render correctly in preview And character counts reflect the localized text length And no placeholder or untranslated source text remains
Workspace Brand Voice Compliance
Given workspace brand voice preferences define preferred terms, banned terms, and style rules When blurbs are generated Then generated text uses preferred terms when contextually relevant And contains zero banned terms And adheres to casing, punctuation, and person/tense rules specified in the style guide And off-brand phrasing is underlined in the editor with inline suggestions And users can apply all suggested fixes with a single Apply Brand Voice action
Safety Checks and Content Guardrails
Given safety policies for sensitive content and off-brand claims are configured When blurbs are generated Then the system scans for sensitive categories (e.g., PII, profanity, hate, NSFW, risky claims) And high-severity findings block copy with a clear reason and redacted view And medium-severity findings surface warnings with one-click Rewrite to fix And a safety status badge (Pass/Warnings/Blocked) is shown per variant And blocked variants cannot be copied until resolved
Copy-to-Clipboard Action with Smart Link
Given at least one blurb variant is generated When the user clicks Copy for a variant Then the clipboard receives exactly the rendered text for that channel including the trackable smart link and any hashtags/emojis as previewed And a success toast appears within 300 ms and auto-dismisses after 2 seconds And the copied link resolves to the share page and records a test ping in analytics when opened And the action works on the latest versions of Chrome, Safari, Firefox, and Edge
Timestamped Context and Deep Links
Given each blurb must reference a specific moment in the media When blurbs are generated Then timestamps are formatted consistently as [mm:ss] for durations under 1 hour or [hh:mm:ss] for 1 hour or longer And the timestamp text deep-links to the corresponding moment on the share page via the smart link And for channels that do not support hyperlinking in text, the URL includes a time parameter and the timestamp appears as plain text And clicking the link starts playback within ±1 second of the referenced time
Trackable Smart Link & UTM Builder
"As a marketer, I want a trackable short link with UTMs so that I can attribute traffic and performance to specific channels and campaigns."
Description

Create a short, branded redirect link (e.g., csprk.co/abc123) for each share that points to the generated share page. Automatically append channel-aware UTM parameters and support per-variant identifiers for attribution (e.g., email vs. LinkedIn post). Provide a QR code, copy-to-clipboard, and quick regenerate options. Ensure GDPR compliance with consent banners on the share page where applicable and honor Do Not Track. Store click events with basic metadata and support timestamp deep links. Allow enabling custom domains where available.

Acceptance Criteria
Branded Short Link Creation, Redirect, and Custom Domain Support
Given a published share page exists When the user activates One-Tap Share Then a unique HTTPS short link is created under the default domain (csprk.co) within 300 ms P95 using a 6–8 character slug [a–z0–9] And a GET to the short link returns a single-step HTTP 302 redirect to the share page within 200 ms P95 And slugs are case-insensitive and exclude ambiguous characters (0,O,1,l) And the link is returned in the UI and API response And if a verified custom domain is enabled for the workspace, the short link is created under that domain with a valid TLS certificate And if the custom domain is unverified or misconfigured, the system falls back to csprk.co and surfaces a non-blocking warning
Channel-Aware UTM Auto-Append
Given the user selects a distribution channel (e.g., Email, LinkedIn, X/Twitter, Facebook, Direct, Custom) When generating the share link Then utm_source, utm_medium, and utm_campaign are appended according to the selected channel mapping And utm_content includes a stable variant identifier when variants are used And existing UTM parameters on the destination are preserved without duplication unless the user explicitly overrides And all UTM parameters are percent-encoded and validated for length (<128 chars each) And the final resolved URL remains <2,048 characters
Per-Variant Attribution Across Channels
Given multiple share variants are created for the same clip (e.g., Email vs LinkedIn) When generating short links for each variant Then each link includes a stable variant identifier (e.g., cs_variant) and/or distinct slug And click events record and attribute variant_id for analytics segmentation And if no variant is specified, events are attributed to "default" And analytics reports can be filtered by channel and variant with consistent totals
QR Code Generation, Download, and Scanability
Given a short link has been generated When the user opens the Share panel Then a QR code representing the short URL is displayed within 200 ms P95 And the QR code is downloadable as PNG and SVG at sizes 256, 512, and 1024 px with error correction level M and a 4-module quiet zone And optional center logo rendering does not reduce scan success below 99% across iOS and Android stock camera apps And scanning the QR code opens the same redirect URL with UTMs intact And 1024 px assets are <500 KB
Copy to Clipboard and Quick Regenerate
Given a short link is visible in the UI When the user clicks Copy Then the link is copied via the async Clipboard API and a success toast appears within 1,000 ms; on permission denial, the URL is focused and selected for manual copy When the user clicks Regenerate Then a new unique slug is created for the same destination within 500 ms P95 and displayed in the UI And previously issued short links remain active and continue to redirect to the same destination And regeneration is rate-limited to 5 attempts per minute per share
GDPR Consent and Do Not Track on Share Page
Given a visitor from an EEA/UK geolocation or where GDPR applies accesses the share page When the page loads Then a consent banner is shown before any non-essential cookies or analytics run And the Do Not Track header, if present, suppresses all non-essential tracking regardless of consent And without consent, only essential redirect and a minimal, cookie-less click event are recorded (timestamp, anonymized IP, user-agent, referrer, link_id, variant_id) And the banner provides Accept, Reject, and Manage options with links to Privacy Policy; consent is stored for 6 months and can be revoked
Click Event Logging and Timestamp Deep Links
Given a short link is clicked When the redirect occurs Then a click event is stored within 1,000 ms P95 including: link_id, destination_id, variant_id, timestamp (UTC), referrer, user_agent, country (derived), anonymized IP (/24 for IPv4, /48 for IPv6), utm_* parameters, and resolved channel And transient storage failures are retried up to 3 times with backoff And duplicate events from the same client within 5 seconds are de-duplicated Given the short link includes a timestamp parameter (t=90 or t=1m30s) When the share page opens Then playback starts at the specified timestamp within ±1 second; invalid values default to 0; UTMs and variant identifiers are preserved
Visibility & Access Controls
"As a team lead, I want to control who can view or download a shared clip so that sensitive content isn’t exposed unintentionally."
Description

Offer per-clip visibility settings: Public, Unlisted, Workspace-only, or Password-protected. Support link expiration, manual revoke, and domain allowlists for embeds. Control download permissions and watermarks. Use signed, time-bound tokens for magic links and log access in an audit trail. Reflect visibility settings consistently across the share page, smart links, and embeds. Provide a simple, prominent guardrail indicating current visibility at publish time to prevent accidental oversharing.

Acceptance Criteria
Per-Clip Visibility Modes & Cross-Surface Consistency
Given I am publishing a clip via One-Tap Share, When I open visibility settings, Then I can select exactly one of: Public, Unlisted, Workspace-only, or Password-protected. Given the clip is Public, When I load the share page, smart links, and embeds, Then the clip is playable without authentication and the same “Public” badge is displayed on all surfaces. Given the clip is Unlisted, When I search or browse the site or workspace, Then the clip does not appear; And when I visit with the direct link, Then the clip is playable. Given the clip is Workspace-only, When a non-member requests the share page or embed, Then access is denied with a 403 message; And when an authenticated workspace member requests it, Then playback succeeds. Given the clip is Password-protected, When I visit the share link, Then I am prompted for a password and cannot access content until it is correct. Given I change the visibility after publishing, When I refresh any existing share page, smart link, or embed, Then the new setting takes effect globally within 10 seconds. Given any visibility setting is active, When I view the publish/share UI, Then the current visibility is shown as a prominent label adjacent to the primary action.
Password-Protected Access Controls
Given a clip is Password-protected, When I set a password of at least 8 characters, Then the password is hashed server-side and never exposed in client logs. Given a correct password is entered, When submitted, Then access is granted for the current browser session for at least 24 hours or until manually revoked; And a success event is logged. Given three consecutive incorrect passwords, When attempts continue, Then a 60-second rate limit is applied to that IP/session. Given I change the clip password, When an existing viewer refreshes, Then they must re-enter the new password and prior sessions are invalidated within 10 seconds. Given an incorrect or missing password/token, When the share page is requested, Then no video stream, transcript, or detailed metadata beyond title is delivered.
Link Expiration and Manual Revoke
Given I generate a magic share link, When I set an expiration interval (1h, 24h, 7d, or custom UTC datetime), Then the link includes a time-bound token that expires accordingly. Given the token is expired, When I access via share page, smart link, or embed, Then access is denied with an "Link expired" message and no media bytes are returned. Given I click Revoke Link, When I confirm, Then all existing tokens for that clip are invalidated within 10 seconds and subsequent requests are denied. Given a revoked or expired link exists, When I generate a new link, Then new tokens are unique and do not re-enable old access. Given I view share analytics, When filtering by clip, Then counts of expired/revoked access attempts are visible for the selected period.
Domain Allowlists for Embeds
Given I configure an embed domain allowlist, When an embed is requested from an allowed domain (including specified subdomain/wildcard rules), Then the player loads and plays. Given an embed is requested from a domain not on the allowlist, When the request is made, Then the player refuses to load playback and shows "Embedding not allowed on this site" and the media API returns 403. Given a wildcard like *.example.com is configured, When an embed is requested from foo.example.com, Then it is allowed; And when from example.co, Then it is denied. Given domains vary by case or include ports, When matching occurs, Then matching is case-insensitive and ports are ignored. Given the allowlist is updated, When an existing embed is refreshed, Then the new rules take effect within 10 seconds.
Download Permissions and Watermarking
Given download is disabled for a clip, When I open the share page or embed, Then no download button or direct file URL is exposed; And unauthorized media storage requests return 403. Given download is enabled, When I click Download, Then a watermarked file is delivered and the watermark includes clip ID, timestamp, and viewer session ID both visibly and steganographically. Given download is enabled but the viewer lacks authorization due to visibility, When they attempt to download, Then the request is denied with 403. Given I toggle the download permission, When I refresh share pages and embeds, Then UI and backend enforcement reflect the change within 10 seconds. Given the watermarking service is unavailable, When a download is requested, Then the system denies the download with "Download temporarily unavailable" and never serves an unwatermarked file.
Signed, Time-Bound Magic Links Integrity
Given I generate a share link via One-Tap Share, When the link is created, Then it contains a signed, time-bound token that encodes clip ID, visibility, expiry, and a nonce. Given the token is tampered with, When validation occurs, Then the request is rejected and logged with reason "Signature invalid". Given the same token is replayed from multiple IPs more than a configured threshold within 5 minutes, When requests continue, Then the system throttles or challenges with CAPTCHA and logs a replay event. Given a token is still valid, When the clip visibility becomes more restrictive, Then future requests with that token are evaluated against the new rules and denied if not permitted. Given a token is near expiry (less than 5 minutes), When an authenticated workspace member accesses, Then a fresh session token is minted for that member without changing the public link.
Audit Trail & Visibility Guardrail at Publish
Given I open the publish modal, When preparing to share, Then a prominent color-coded banner indicates the current visibility (Public, Unlisted, Workspace-only, Password) with a one-line description. Given visibility is Public, When I click Publish, Then I must confirm via an explicit "Make Public" affirmation before the clip is published. Given any access attempt occurs (playback, download, embed), When processed, Then an audit log entry is recorded with timestamp (UTC), clip ID, action, outcome, requester IP (masked /24), user agent, referrer, auth context, and token ID (if any). Given I am a workspace admin, When I view the audit trail for a clip, Then I can filter by action type and date range and export results to CSV; And secrets (passwords, token secrets) are never logged in plaintext. Given retention policies apply, When 180 days elapse by default, Then logs older than the retention window are purged or exportable before deletion according to workspace policy.
Share Performance Analytics
"As a creator, I want to see how my shared clip performs across channels so that I can focus on what drives the most engagement."
Description

Provide a lightweight analytics view per shared clip showing clicks, unique visitors, referrers, device/geo breakdown, average watch time on the share page, and copy-to-clipboard events. Attribute metrics to channels and UTM variants. Display publish status and destination links for each platform. Stream events to Segment or a webhook and support CSV export. Respect privacy regulations with data retention controls and masking of IP addresses where required. Update metrics near-real-time with a small delay and clear data freshness indicators.

Acceptance Criteria
Per-Clip Analytics Metrics Display
Given a published clip share page has received traffic When I open the Analytics view for that clip and select a date range Then I see metrics for total clicks, unique visitors (by distinct anonymous_id), top referrers, device breakdown (mobile/desktop/tablet), geo breakdown (country and region), average watch time (seconds), and copy-to-clipboard events for that range Given the same visitor returns multiple times within the selected range When counting unique visitors Then they are counted once for that range Given visits originate from various sources When rendering referrers Then the top 10 referrers are listed with counts and an aggregated "Direct/Unknown" bucket for missing referrers Given viewers play the video on the share page When calculating average watch time Then average watch time equals the mean of session watch durations rounded to the nearest second and excludes paused/background time beyond 30 seconds inactivity Given a user clicks the "Copy Link" control on the share page When the event fires Then the Copy Events metric increments by 1 within the selected range
UTM and Channel Attribution
Given a click URL contains utm_source, utm_medium, utm_campaign (optional utm_term, utm_content) When the event is recorded Then all downstream metrics for that session are attributed to those UTM values Given a click has no UTM but the share was initiated via a selected channel in ClipSpark (e.g., Email, X/Twitter, LinkedIn) When the event is recorded Then the session is attributed to that channel Given both a selected channel and UTM parameters exist When attributing Then UTM values take precedence and channel is derived from utm_source mapping rules Given I filter the analytics by channel or any UTM value When I apply the filter Then all displayed metrics and breakdowns reflect only matching events Given a visitor interacts with multiple UTM variants in the range When counting unique visitors per variant Then the visitor is unique within each variant’s breakdown but not double-counted in the overall unique visitors total
Publish Status and Destination Links
Given a clip has been shared to one or more platforms When I open the Analytics view Then each platform shows its publish status (Draft, Scheduled, Published, Failed, Broken) and a destination URL Given a destination URL is displayed When I click it Then it opens in a new tab and responds with HTTP 200–399, otherwise the UI shows an error state with last checked timestamp Given a publish job fails When I view its status Then I see status = Failed, the last error message, and a Retry action Given a scheduled publish time passes and the platform confirms publication When I refresh the view Then the status updates to Published within 2 minutes
Event Streaming to Segment or Webhook
Given Segment streaming is enabled When a share page event occurs (page_view, link_click, copy_link, video_play, watch_time_update) Then a Segment track call is sent within 60 seconds including clip_id, share_id, anonymous_id or user_id (if known), timestamp (ISO 8601 UTC), channel, UTM fields, referrer, device_type, country, region, and event-specific props Given a custom webhook endpoint and secret are configured When events occur Then POST requests are sent within 60 seconds with JSON payloads matching the documented schema and an HMAC signature header; each payload includes a stable idempotency_key Given the destination returns a transient 5xx or times out When delivering events Then retries occur with exponential backoff up to 6 attempts; after max retries the event is marked dead-letter with an operator-visible error Given retries cause duplicate deliveries When the receiver uses idempotency_key Then no duplicate records are created
CSV Export of Analytics
Given I request a CSV export for a clip with a selected date range and optional filters (channel and UTM) When the export completes Then the CSV contains event-level rows with columns: event_type, event_timestamp (ISO 8601 UTC), clip_id, share_id, channel, utm_source, utm_medium, utm_campaign, utm_term, utm_content, referrer, device_type, country, region, watch_time_seconds (nullable), ip_masked (true/false) Given I compare UI metrics to the exported CSV for the same filters When I aggregate the CSV Then totals match the UI within 0.5% for counts and within 1 second per session for average watch time Given an export exceeds 50,000 rows When processing Then a downloadable link is emailed to the requester and remains valid for 24 hours
Privacy, IP Masking, and Data Retention Controls
Given a viewer is located in the EU/EEA When persisting analytics events Then IP addresses are masked (IPv4 last octet zeroed; IPv6 truncated to /48), and location is stored at country and region only Given the workspace data retention is configured to N days (default 180) When an event’s age exceeds N days Then it is purged from analytics storage and excluded from UI and exports Given a viewer has Do Not Track enabled or declines consent (where consent is required) When tracking Then only strictly necessary events are recorded without identifiers, no cookies are set, and unique visitors are not incremented Given a verified deletion request for a viewer identifier When processed Then all matching analytics events are deleted within 30 days and excluded from future exports
Near-Real-Time Updates and Data Freshness Indicators
Given new analytics events are generated When I view the analytics dashboard Then metrics reflect events within 2 minutes for at least 95% of events and within 5 minutes for 99.9% Given I open the analytics view When it loads Then a Last updated timestamp shows the data watermark, and the view auto-refreshes every 60 seconds while the tab is active Given the latest data is older than 5 minutes When displaying the dashboard Then a yellow Data may be delayed banner appears until freshness is restored Given a processing outage occurs and later recovers When backfill completes Then metrics are retroactively updated for the gap and the freshness banner is cleared

Instant Sample

No file yet? Spin up a persona-matched sample project that demonstrates the full Fastlane flow—upload, auto-clips, polish, share—in under three minutes. Learn by doing and see exactly what your own content will look like.

Requirements

Persona-Matched Sample Selection
"As a first-time user, I want a persona-matched sample project created for me so that I can immediately see a realistic version of how ClipSpark will handle content like mine."
Description

Provide a guided start that selects or infers the user’s persona (e.g., Educator, Podcaster, Knowledge Worker) and locale to spin up a representative sample project. The flow should surface default templates, style presets, and tone settings aligned to the persona, pre-fill project metadata (title, description, speaker names when available), and clearly label the project as a sample. Entry points include the empty state dashboard, onboarding checklist, and an in-app CTA. The selection should be overridable, persist user choices for future sessions, and integrate with existing template/theming systems without introducing new template types.

Acceptance Criteria
Persona and Locale Capture from Empty State
Given a new user with no saved persona or locale When they click the "Create Instant Sample" CTA on the empty-state dashboard Then a modal appears within 1 second presenting persona options (Educator, Podcaster, Knowledge Worker, Other) and a locale selector defaulted to the browser locale And both persona and locale are required fields with validation preventing continuation until selected And upon confirmation, the flow proceeds to sample project creation using the chosen persona and locale
Inferring and Overriding Existing Persona/Locale
Given a returning user with previously saved persona and locale When they launch Instant Sample from any entry point Then the selection modal pre-selects the saved persona and locale And the user can override either before confirmation And upon confirmation, the most recent selections are persisted for future sessions And if the user cancels, previously saved values remain unchanged
Persona-Aligned Defaults Applied to Sample
Given a selected persona When the sample project is created Then default template, style preset, and tone settings mapped to that persona are auto-selected And these selections are visible and adjustable in the project setup panel before processing And mappings exist for Educator, Podcaster, and Knowledge Worker personas (no null defaults) And the caption language defaults to the selected locale where supported
Project Metadata Pre-Filled
Given persona and locale have been selected When the sample project opens Then the project title is pre-filled as "Sample — {Persona}" and localized based on the selected locale And the description is pre-filled with persona-appropriate copy in the selected locale And speaker names are pre-filled when available from the sample asset, otherwise use persona-appropriate generic placeholders (e.g., Host, Guest) And all metadata fields remain user-editable
Clear Sample Labeling Across UI
Given the project is a sample When viewing the dashboard card, project header, and share page preview Then a persistent, non-editable "Sample" badge appears adjacent to the project title in all three locations And the badge is present in light and dark themes and meets contrast accessibility standards And exported media is not automatically watermarked solely due to being a sample
Unified Entry Points Trigger the Same Flow
Given the user accesses Instant Sample from the empty state dashboard CTA, the onboarding checklist, or an in-app CTA When they click any of these entry points Then the same persona/locale selection modal launches with identical options and behavior And the analytics event "instant_sample_started" is emitted with a source attribute (dashboard|checklist|in_app) And upon confirmation, the event "instant_sample_confirmed" is emitted including the selected persona and locale
Integration Uses Existing Templates/Theming Only
Rule: All sample projects must reference existing templateId and themeId values from the current catalog; no new template types are introduced for sample flows Rule: Template.type for sample projects must be one of the existing allowed types; no value equals "sample" or any new type Rule: The theming and templating APIs invoked are identical to those used in standard project creation (same endpoints and payload shapes) Rule: Database schema and seed data are unchanged by the sample flow; verification includes migration review and catalog integrity check
Prebuilt Sample Asset Library
"As a product evaluator, I want high-quality sample content that fits my role and language so that the demo feels relevant and trustworthy."
Description

Maintain a curated, licensed library of short, diverse sample videos and manifests per persona and major languages that demonstrate key ClipSpark capabilities. Each sample includes a CDN-hosted source file (multiple resolutions), transcripts, speaker segmentation, chapter markers, and predefined clip candidates to ensure a complete flow without waiting on compute-heavy steps. Assets are watermarked and clearly flagged as sample-only, with metadata specifying usage rights, localization, and duration bounds. The library exposes a versioned manifest API consumed by the app to fetch compatible assets based on persona and locale.

Acceptance Criteria
Persona- and Locale-Based Sample Selection
Given a client requests the manifest with persona=P and locale=L When the API is queried Then the response contains only assets whose persona equals P and whose locale or language_tag matches or maps to L And each returned asset has status "active" And if no matching assets exist the response is an empty list with HTTP 200
Coverage Across Personas and Major Languages
Given a configured set of target personas S and major languages M When the library is published Then there exists at least one active sample asset for every combination of persona in S and language in M And within each persona-language group the assets include at least two distinct metadata.category tags to demonstrate diversity
Sample Asset Package Completeness and Integrity
Given an asset listed in the manifest When validating its components Then the asset includes: cdn_sources with at least 2 distinct quality variants; transcript; speaker_segments; chapters; and clip_candidates And all referenced URLs return HTTP 200 over HTTPS with appropriate content-types And all timecodes (transcript segments, speaker_segments, chapters, clip_candidates) fall within [0, asset.duration] with no overlaps where not permitted And each clip_candidate has start < end and duration within any defined clip_duration_bounds
Manifest Versioning and Compatibility
Given the client sends Accept-Version = V that is supported When requesting the manifest Then the response includes version = V and validates against schema V (as referenced by schema_url) Given the client omits Accept-Version When requesting the manifest Then the response includes version = current_stable and validates against that schema Given the client sends an unsupported Accept-Version When requesting the manifest Then the API responds with HTTP 406 (or 400) and includes a supported_versions array
Precomputed Derivatives Ready for Fastlane Flow
Given an asset is provided for Instant Sample use When the manifest is inspected Then transcript.status, speaker_segments.status, chapters.status, and clip_candidates.status are all "ready" And metadata.derivatives_ready is true and processing_required is false And all derivative artifacts are directly retrievable via URLs without initiating compute jobs
Watermarking and Sample-Only Labelling
Given any sample asset When the manifest is inspected Then metadata.sample is true and metadata.sample_label is present And metadata.watermark is true and watermark_spec is provided Given frames are extracted at predefined check_points When checked against watermark_spec Then the embedded visual watermark is detected on the video content
Usage Rights, Localization, and Duration Bounds Enforcement
Given an asset in the manifest When validating metadata Then usage_rights includes license_type, attribution, and expires_at (ISO-8601) And if now > expires_at the asset is excluded from API responses And localization.language_tag conforms to BCP 47 and matches the transcript and chapter language tags And asset.duration respects metadata.duration_bounds (min..max) when defined, and all clip_candidates fall within [0, asset.duration]
Fastlane Flow Orchestration (Sub-3-Minute Demo)
"As a new user, I want to experience the complete ClipSpark workflow quickly so that I understand the value without waiting for long processing times."
Description

Execute the full Fastlane sequence—upload, analyze, auto-clip, caption, summarize, and highlight generation—using a hybrid of cached outputs and accelerated processing to complete in under three minutes at the 95th percentile. The orchestrator should emit the same progress events and UI states as real projects, handle retries and fallbacks, and degrade gracefully if a step is slow by swapping in precomputed artifacts. It must log step timings, display a progress timeline, and ensure feature parity with the production pipeline while isolating sample runs from billing and quotas.

Acceptance Criteria
P95 Sub-3-Minute Completion SLA
Given a baseline QA environment and a batch of at least 200 Instant Sample runs at up to 5 concurrent sessions over 1 hour When measuring total duration from 'upload_started' to 'demo_complete' Then the 95th percentile completion time is <= 180 seconds, median <= 120 seconds, and max <= 210 seconds And zero runs exhibit >5 seconds gap between consecutive progress events And no run emits an unhandled error
Production Event and UI State Parity
Given a real project run and an Instant Sample run of the same pipeline version When capturing emitted progress events and UI state transitions Then the event sequence names, order, and JSON schema fields are identical, excluding identifiers and a sample=true flag And timestamps are monotonic non-decreasing per run And user-visible UI states appear in the same order with identical labels and icons
Graceful Degradation via Precomputed Artifacts
Given any pipeline step that errors or exceeds its per-step budget (Analyze 40s, Auto-Clip 30s, Caption 30s, Summarize 20s, Highlight 30s) When the condition is detected Then the orchestrator swaps in a precomputed artifact for that step within 2 seconds And emits a 'step_fallback_used' event with step_name, reason, and source='cached' And the UI continues without modal interruption and marks the step as 'Accelerated' And the final deliverables remain available with valid download/share links
Step Timing Logs and Progress Timeline
Given an Instant Sample run When it completes Then logs contain for each step: step_name, start_ts, end_ts, duration_ms, outcome in {'real','cached'}, retry_count, fallback_used boolean, error_code nullable, and host_id And logs are persisted to the telemetry store within 5 seconds of run completion with 30-day retention And the on-screen timeline displays each step with duration and a total time, with hover tooltip showing outcome And the sum of displayed step durations is within ±2 seconds of the measured total duration
Billing and Quota Isolation
Given a customer with zero billable usage in the prior hour When they run an Instant Sample Then no billable usage or credits are recorded for the customer in billing/usage stores And third-party API calls during the run are tagged sample=true and excluded from quota enforcement And the project is marked type='sample' and excluded from productivity analytics And running a real project immediately after shows no carryover limits or charges attributable to the sample
Output Format and Quality Parity
Given an Instant Sample run that completes without manual edits When retrieving generated outputs Then captions validate against production schemas (WebVTT/SRT) with per-cue timestamps aligned within ±300 ms to associated audio segments And summaries meet production length constraints (<=200 words) and pass readability checks (Flesch–Kincaid grade <=10) And highlight clips count is between 3 and 7, each with non-overlapping start/end times and valid thumbnail previews And all outputs are downloadable and shareable via the same endpoints used by real projects
Retry and Backoff Without Exceeding SLA
Given a transient failure (HTTP 5xx or timeout) in any step When the orchestrator retries with exponential backoff (initial 1s, factor 2, max 2 retries) Then the step either succeeds within the total run SLA or triggers cached fallback without the run exceeding 180 seconds And all retries and outcomes are reflected in events and logs with retry_count incremented And operations are idempotent, producing no duplicate assets or events across retries
In-Sample Editing Sandbox
"As a hands-on learner, I want to edit the sample clips and captions so that I can assess how easy it will be to polish my own content."
Description

Enable hands-on editing of the sample outputs, including clip trimming, reorder, caption edits, title and description tweaks, thumbnail selection, and style changes. Edits are non-destructive, autosaved, and constrained to a sandbox that prevents exporting raw media while allowing full interaction with the existing editors. The sandbox persists as a temporary project with clear labeling and can be reset to defaults. Keyboard shortcuts, undo/redo, and draft indicators should work identically to real projects to build user confidence.

Acceptance Criteria
Non-Destructive Edits and Reset in Sample Sandbox
Given I am in the Instant Sample project, When I make edits (trim, reorder, caption text, title, description, thumbnail, style), Then the original sample source media is not modified and edits are stored as sandbox revisions. Given I have made any edits, When I click Reset to Defaults and confirm, Then all edits are discarded and the project returns to its initial sample state within 3 seconds. Given I initiate Reset to Defaults, When I cancel the confirmation, Then no changes are lost and the project remains in its current edited state.
Autosave and Draft Indicators in Sample Sandbox
Given I am online in the Instant Sample project, When I stop interacting for 2 seconds after a change or navigate between views, Then the latest changes autosave within 2 seconds and the indicator changes from “Saving…” to “Saved”. Given a change has been made, When autosave is in progress, Then a visible “Saving…” draft indicator appears within 100 ms of the change and remains until save completes. Given I go offline while editing, When I continue making changes, Then an “Offline—changes queued” indicator appears and all queued edits sync within 5 seconds of reconnecting without data loss. Given a save attempt fails, When 3 retries within 30 seconds also fail, Then an inline error appears with actions to Retry and Copy error ID, and no edits are discarded.
Keyboard Shortcuts and Undo/Redo Parity
Given the sample editor has focus, When I press Cmd/Ctrl+Z, Then the last change is undone; When I press Cmd/Ctrl+Shift+Z (or Cmd/Ctrl+Y on Windows), Then the last undone change is redone. Given I perform a series of edits, When I invoke Undo repeatedly, Then at least the last 50 actions are undoable in order; When I make a new change after undoing, Then the redo stack is cleared. Given I use core shortcuts (Space = Play/Pause, S = Split, Arrow keys = nudge 1 frame, Shift+Arrow = nudge 10 frames), When used in the sample, Then they produce the same effects as in real projects.
Clip Trimming and Reordering Behavior
Given a timeline with multiple clips, When I drag a clip to a new position, Then the new order is applied and reflected in playback within 300 ms and persists after page refresh. Given a clip has in/out handles, When I trim using handles or nudge keys, Then trims apply with ±1 frame accuracy and the displayed durations update immediately. Given captions are attached to clips, When I trim a clip, Then captions outside the new boundaries are hidden and boundary-intersecting captions are cropped without shifting timestamps of other clips. Given I make several trims and reorders, When I switch between Clips, Captions, and Share views, Then the timeline state remains consistent.
Caption Editing, Timing, and Styling in Sandbox
Given the caption editor is open, When I edit caption text and commit (Enter or focus change), Then the updated text is saved and immediately visible in playback. Given I adjust caption timing by dragging edges or typing timecodes, When I release or commit, Then start/end times update with 100 ms precision and do not overlap adjacent captions. Given I change caption styles (font, size, color, background, position), When I preview the clip, Then the new styles render in the player and persist on revisit. Given I perform caption edits, When I use Undo/Redo, Then both text and timing/style changes are reverted or re-applied accordingly.
Sandbox Labeling, Constraints, and Persistence
Given I am in the Instant Sample project, Then a persistent “Sample Sandbox” label is visible in the header and in the project list entry for this project. Given I attempt to export or download raw/original media, When I click any Export/Download control for source or timeline media, Then the action is disabled or hidden and an explanation indicates export of raw media is disabled in the Sample Sandbox. Given I interact with editors (Clips, Captions, Thumbnails, Styles), Then all editing controls are available as in real projects, excluding raw export actions. Given I close the browser or sign out, When I return with the same account, Then the Instant Sample project and its last autosaved state are restored.
One-Click Share for Sample Outputs
"As a prospective user, I want to share the sample highlights with my team so that we can quickly evaluate whether ClipSpark meets our needs."
Description

Allow creation of shareable links for sample highlight reels and summary pages with prominent “Sample” labeling and optional watermarking. Links include social/meta previews, basic engagement analytics, and default privacy settings (unlisted with expiration). Users can copy a single link or share directly to supported destinations without requiring file exports. The system should prevent confusion by disabling download of sample source media and clearly communicating limitations.

Acceptance Criteria
Shareable Link Creation for Sample Reels and Summary Pages
Given a user has an Instant Sample project with a generated highlight reel or summary page When the user clicks "Share Sample" Then the system generates a unique, unguessable URL for each selected sample asset within 2 seconds And the URL resolves to a publicly viewable sample page without requiring authentication And the page returns HTTP 200 and renders the asset And the URL can be invalidated by the owner from Share settings, after which it returns HTTP 410 Gone
Prominent "Sample" Labeling and Optional Watermark
Given a viewer opens a shared sample highlight reel or summary page via the generated link Then a visible "Sample" label is displayed in the page header and above the player on all breakpoints And if the "Watermark sample outputs" toggle is enabled before sharing, a semi-transparent repeating "Sample" watermark overlays the video, including in full-screen mode And if the toggle is disabled, no watermark appears on the video And labels/watermarks do not appear on non-sample projects
Default Privacy: Unlisted With Expiration
Given the user opens the Share modal for a sample asset Then the default visibility is Unlisted (link-only access; no authentication required) And an expiration date is prefilled to 14 days from now and is required And the expiration can be adjusted between 1 and 90 days but cannot be removed When the expiration is reached Then the link returns an expiration page with HTTP 410 Gone and no media bytes are served And the page includes meta robots noindex,nofollow and is excluded from sitemaps
Social/Meta Preview Rendering
Given a share URL for a sample asset is fetched by social crawlers Then the page serves Open Graph and Twitter Card tags with title prefixed "Sample — {asset title}", a description <=160 characters, and a JPEG/PNG thumbnail And the preview image contains a visible "Sample" badge When the link is pasted into Slack, LinkedIn, X/Twitter, Facebook, or iMessage Then a rich preview renders showing the thumbnail and title And Facebook Sharing Debugger and LinkedIn Post Inspector report HTTP 200 with no critical errors
Share Actions: Copy Link and Direct Share (No Export)
Given the Share modal is open for a sample asset When the user clicks Copy Link Then the share URL is placed on the clipboard and a confirmation toast appears within 1 second When the user chooses Share to LinkedIn/Twitter/Email Then the respective native/share dialog opens prefilled with the URL and a default message And no file export or download options are shown for sample assets in this flow
Download Restrictions and Limitations Messaging
Given any viewer (including the owner) is on a shared sample page Then controls or endpoints to download the original source media are not present And attempts to fetch known source media URLs return HTTP 403 Forbidden with zero bytes streamed And a notice is displayed: "This is a sample. Some actions (downloads, edits) are limited. Create your own project to export." And links/buttons direct the user to start their own project
Basic Engagement Analytics for Shared Samples
Given a share URL for a sample asset is active When viewers open the link and play the highlight reel Then the system records total views, unique viewers (cookie-based), and average watch time And analytics exclude the owner's views when authenticated or within the same browser session And metrics are visible to the owner in the sample project's Analytics panel within 5 minutes of events And UTM parameters in the URL are preserved and attributed in analytics
Convert Sample to Real Project
"As an engaged evaluator, I want to seamlessly switch from the sample to my own video so that I can apply what I learned without rebuilding settings."
Description

Provide a prominent CTA to replace sample assets with the user’s own file or recording source while preserving the selected persona, style presets, clip selection logic, and project structure. The conversion flow supports file upload, URL import, or integration connectors, validates account limits, and prompts users to confirm carry-over settings. Upon confirmation, the system creates a new real project, migrates applicable settings, and links from the sample project to track conversion.

Acceptance Criteria
CTA Visibility and Placement in Sample Project
Given I am viewing an Instant Sample project in any step (Upload, Auto-clips, Polish, Share) When the page loads on desktop or mobile Then a primary CTA labeled "Use Your Own Content" is visible without scrolling and is keyboard-focusable with an accessible name "Convert sample to real project" And when I activate the CTA via click or keyboard Then a Conversion modal opens within 1 second
Multi-Source Conversion Flow with Validation
Given the Conversion modal is open When I select Upload and choose a supported media file (mp4, mov, mp3, wav) within my plan’s size and duration limits Then the file is accepted and I can proceed to confirmation When the selected file exceeds limits Then I see a clear limit message with an upgrade option and the Proceed action is disabled until resolved When I select URL Import and enter a reachable media URL Then the system validates reachability, format, and length before allowing Proceed; invalid inputs show inline errors When I select an integration connector (e.g., Google Drive, Dropbox, Zoom) Then I am prompted to authorize if not connected, and on success I can pick a source; on cancel I return to the modal without losing selections
Confirm and Carry Over Settings
Given a sample project has a persona, style presets, clip selection logic, and project structure When I reach the confirmation step Then I see a summary of carry-over settings with toggles defaulted to ON for each (Persona, Style Presets, Clip Selection Logic, Project Structure) And I can expand to view/edit each setting before confirming When a setting is incompatible with the chosen source (e.g., no video track for visual presets) Then it is auto-adjusted or disabled with an explanatory tooltip and does not block conversion And when I confirm Then the chosen carry-over selections are persisted to the new project
Create Real Project and Preserve Sample
Given I confirm conversion with a valid source When the system creates the new project Then a real project record is created with a unique ID and initial status "Processing" within 10 seconds (excluding upload/import time) And the sample project remains unchanged and accessible And the new project inherits selected persona, style presets, clip selection logic, and project structure When clip generation runs on the new asset Then progress is displayed and, on success, initial clips appear; on failure, an error banner with retry is shown
Post-Conversion Linking and Tracking
Given a new project has been created from a sample When I view the originating sample project Then I see a "Converted to" link pointing to the real project When I view the real project Then I see a "Converted from sample" tag with a link back to the sample And analytics events are emitted: sample_conversion_started, sample_conversion_succeeded or sample_conversion_failed, including user ID, sample ID, new project ID, and source type
Reliability, Idempotency, and Progress Feedback
Given I initiate conversion and begin upload/import When the upload/import is in progress Then I see a progress indicator with step-level status and estimated time remaining; on network interruption, the upload auto-resumes or provides a manual Resume without restarting from 0 When I click the Convert CTA multiple times for the same sample and same source within 5 minutes Then only one real project is created and subsequent attempts deep-link to the existing project When connector authorization expires mid-flow Then I am prompted to re-authorize and can continue without losing prior selections
Telemetry, SLA, and Cleanup Controls
"As a product owner, I want visibility into usage, performance, and conversion of Instant Sample so that we can optimize the experience and manage cost and reliability."
Description

Instrument end-to-end metrics for the Instant Sample feature, including entry-point CTR, time-to-completion per step, edit interactions, share actions, and conversion to real project. Enforce an operational SLA of sub-180 seconds at the 95th percentile with alerts and circuit breakers that fall back to precomputed artifacts if live processing lags. Implement automated cleanup of stale sample projects and links after a configurable retention window to control costs and maintain privacy. Support feature flags and A/B tests for iterative improvement.

Acceptance Criteria
Entry-Point CTR Telemetry Accuracy & Availability
Given an eligible user loads a page with the Instant Sample entry point, When the entry point is rendered, Then a view event "instant_sample.entry_view" is emitted exactly once per page view with fields: session_id, user_id (nullable), persona, experiment_variant, timestamp_ms, request_id, view_id. Given the user clicks the Instant Sample entry point, When the click occurs, Then a click event "instant_sample.entry_click" is emitted within 200ms with fields matching the view schema plus view_id reference and click_position, and duplicate clicks within 5 seconds are deduplicated per session_id. Given view and click events are ingested, When metrics are queried, Then CTR = distinct(clicks)/distinct(views) is available in the metrics store within 60 seconds at P95, with 99% availability and 90-day retention. Given ingestion delays or outages, When events are retried, Then at-least-once delivery is guaranteed and idempotency keys prevent duplicate counts.
Step-Level Time-to-Completion Metrics & Session Cohesion
Given a user starts the Instant Sample flow, When each step occurs (start, artifacts_ready, polish_opened, share_completed), Then a step event with step_name, timestamp_ms, session_id, persona, experiment_variant is emitted and correlated to the same session_id. Given all step events for a session, When computing durations, Then per-step durations and end-to-end time_to_completion_ms are computed server-side and written to a "instant_sample.session_summary" record within 60 seconds at P95. Given network interruptions, When step events arrive out-of-order, Then server-side ordering by timestamp_ms reconstructs accurate durations, and sessions missing terminal events are marked status="incomplete" after 30 minutes of inactivity. Given a QA session, When inspecting the summary record, Then it contains fields: session_id, started_at, completed_at (nullable), time_to_completion_ms (nullable), step_durations, status, persona, experiment_variant.
SLA Compliance Monitoring & Alerting
Given production traffic, When calculating end-to-end time_to_completion_ms, Then a rolling 5-minute P95 is computed per persona and experiment_variant and displayed on a dashboard with P50/P95/P99. Given the operational SLA, When any segment’s P95 exceeds 180,000 ms for 2 consecutive windows, Then a HIGH alert is sent to PagerDuty within 2 minutes and a Slack notification is posted to #ops-instant-sample. Given alert recovery, When the segment’s P95 is below 180,000 ms for 3 consecutive windows, Then the alert auto-resolves and status is reflected on the dashboard. Given metrics anomalies, When no data is received for a segment during a window, Then the dashboard marks the segment as "no data" and triggers a WARNING alert if the condition persists for 10 minutes.
Circuit Breaker Fallback to Precomputed Artifacts
Given live processing queue depth and ETA forecasts, When predicted P95 completion for new sessions exceeds 150,000 ms OR observed P95 exceeds 180,000 ms for 2 consecutive windows, Then the circuit breaker activates within 30 seconds and new sessions are routed to precomputed persona-matched sample artifacts. Given a session starts after activation, When the user proceeds through the flow, Then all steps complete without live processing and end-to-end P95 for fallback sessions is <= 90,000 ms. Given circuit breaker activation, When conditions return to normal for 3 consecutive windows, Then the circuit breaker automatically deactivates and new sessions return to live processing. Given operator override, When the feature flag fallback_force_on or fallback_force_off is toggled, Then routing updates within 60 seconds and the change is logged with actor, timestamp, and reason.
Edit and Share Interaction Telemetry Coverage & Privacy
Given a user edits captions, trims, or reorders highlights in the Instant Sample, When the action is performed, Then an edit event is emitted with action_type, clip_id, session_id, timestamp_ms, and numeric deltas (e.g., chars_changed, ms_trimmed, new_position) without sending raw content or PII. Given a user opens the share dialog and completes a share, When the share is created, Then a share event records share_channel, session_id, sample_id, timestamp_ms, and link_id, and the share link is retrievable via audit logs. Given unreliable networks, When the client cannot send telemetry, Then events are queued locally and retried for up to 24 hours with exponential backoff and idempotency keys to avoid duplicates. Given data governance, When data is stored, Then edit and share events are retained for 90 days and comply with the system’s redaction policy (no raw transcript text).
Automated Cleanup of Stale Sample Projects & Links
Given a configurable retention window (default 7 days, range 1–30), When a sample project’s last_activity_at exceeds the window and is marked is_sample=true, Then the cleanup job deletes the project, associated media assets, and derived artifacts, and revokes any signed URLs. Given share links for deleted samples, When a user visits a deleted link, Then the endpoint returns HTTP 410 Gone and displays a generic expiration message without revealing prior content. Given storage and CDN, When assets are deleted, Then corresponding CDN cache entries are invalidated within 10 minutes and no asset is publicly accessible after that period. Given operational reliability, When deletions fail due to transient errors, Then the job retries with exponential backoff up to 5 times and records failures to an audit log with resource identifiers; success rate per run is >= 99.5%.
Feature Flags and A/B Test Segmentation with Guardrails
Given feature flags for Instant Sample (enable_instant_sample, pipeline_variant, fallback_force_on/off), When a session begins, Then exposure is logged before the first telemetry event with session_id, user_id (nullable), flag states, and experiment_variant (if applicable). Given an active A/B test, When traffic is assigned, Then bucketing is deterministic by user_id (else session_id) with a 50/50 split and <1% imbalance over 10,000 sessions, and cross-device users remain in the same bucket. Given segmented metrics, When dashboards are viewed, Then CTR, step durations, and SLA P95 are filterable by experiment_variant and flag states, and include confidence intervals for conversion to real project. Given guardrails, When any variant’s P95 exceeds 180,000 ms for 3 consecutive windows, Then the variant is automatically disabled via flag within 2 minutes and an alert is sent with the disabling reason.

Product Ideas

Innovative concepts that could enhance this product's value proposition.

Roleweave SSO

Enterprise SSO with SCIM, plus clip-level permissions and watermarking. Enforce export controls and retention policies across teams from one dashboard.

Idea

Click-Through Clip Cards

Auto-generate shareable cards that deep-link to exact timestamps with animated waveform previews. Track opens and watch-time to prove which moments drive clicks.

Idea

Citation-Locked Quotes

Create tamper-evident quotes bound to audio via word-level timestamps and cryptographic hashes. Export courtroom-ready exhibits with inline source links.

Idea

Smart Chapter Forge

Forge AI chapters with learning objectives, slide references, and quiz seeds. One click exports to LMS modules with SCORM-compatible timestamps.

Idea

Snippet Paywall Drops

Package highlight reels behind a paywall with metered previews. Stripe-powered one-off purchases and subscriber access unlock per-clip analytics and refunds.

Idea

Live Moment Radar

Detect quotable spikes during live streams using sentiment and keyword surges. Drop real-time markers, ping Slack, and auto-spin post-event highlight reels.

Idea

First-Clip Fastlane

Guided onboarding that turns a new user's first upload into three polished clips in under three minutes. Built-in tooltips, sample projects, and instant sharing.

Idea

Press Coverage

Imagined press coverage for this groundbreaking product concept.

P

ClipSpark Launches AI Engine That Transforms Long‑Form Video into Captions, Summaries, and One‑Click Highlights

Imagined Press Article

San Francisco, CA – September 13, 2025 – ClipSpark today announced the general availability of its AI-driven platform that analyzes long-form video to produce accurate, timestamped captions, concise summaries, and one-click highlight clips. Built for educators, podcasters, and knowledge workers who repurpose recordings every day, ClipSpark pinpoints context-rich moments automatically—cutting scrubbing and manual editing time by 70%, tripling shareable output, and returning an average of six hours to every user each week. The launch comes as organizations of every size struggle to keep up with growing video libraries from lectures, webinars, interviews, and meetings. ClipSpark ingests uploads and links from major platforms, then generates a set of publish-ready assets in minutes, complete with timestamps, speaker attribution, and on-brand visuals. Users can export to the LMS, social channels, and internal knowledge bases with a single click, or embed privacy-first Clip Cards anywhere. “Long-form video is where the best ideas live—and where they often get lost,” said Alex Rivera, CEO and co-founder of ClipSpark. “We built ClipSpark to find the signal fast, preserve context, and make high-quality clips easy for anyone to share. It’s not just about speed; it’s about trust. Captions are accurate, quotes are defensible, and highlights retain the meaning that matters.” From first-time creators to enterprise teams, ClipSpark adapts to a wide range of workflows. New users can choose a quick persona—Podcaster, Educator, Sales, or Research—and Persona SnapStart applies proven defaults for clip runtime, caption style, and export settings. Goal Picker tells the system what you’re trying to ship—Promo, Recap, Quote Reel, or Study Aid—so ClipSpark tunes length, tone, and crop for that outcome. Clip Trio instantly produces three distinct cuts—Hook, Context, and Takeaway—from the first upload, each timestamped and captioned for immediate publishing. “I used to spend Friday afternoons scrubbing lectures, hunting for the same three minutes students kept asking about,” said Professor Maya Chen, Instructional Design Director at Northfield University. “With ClipSpark, I drag in a recording and get clean captions, a study-ready summary, and highlight clips aligned to my learning goals. The time savings are real, and the student experience is better because they can jump right to the moment that matters.” Indie podcasters are seeing similar gains. “My episode turnaround dropped from two days to a few hours,” said Diego Alvarez, host of Code Coffee Chats. “ClipSpark nails captions, writes tight show notes, and surfaces social-ready clips that actually perform. It’s like getting a producer without losing my voice.” For sales and enablement teams, ClipSpark identifies crisp objection-handling moments and customer soundbites. “We ship micro-coaching clips to our reps within an hour of a call,” said Priya Shah, sales enablement manager at AcmeCloud. “Our library has grown 3x, but approval time has gone down because every clip is anchored to the original audio with timestamps.” ClipSpark’s accuracy and context-preserving design are reinforced by optional governance and integrity features for teams in regulated industries. ClipGuard Links enable expiring, SSO-gated access to clips with dynamic, identity-stamped watermarks. Audit Ledger captures a tamper-evident history of access, exports, and policy changes, while Policy Blueprints help organizations jumpstart compliance with prebuilt templates for retention and export controls. For customers who need court-grade confidence, ClipSpark’s HashLock Anchors can bind quotes to exact audio at the word level, with a public Open Verifier available for third parties. Accessibility is first-class by design. The platform produces high-accuracy, timestamped captions and transcripts that help teams meet WCAG/ADA standards. Admins can enforce data residency and export controls via GeoFence Exports and route exceptions through Delegated Approvals, keeping content compliant without slowing the work. Availability and pricing ClipSpark is available today worldwide. Users can start free with limited exports and upgrade to Pro and Team plans for expanded hours, brand customization, and governance features. Enterprise plans include SCIM SmartMap for role-based provisioning, SIEM log streaming, and advanced policy controls. Education and nonprofit discounts are available. Roadmap highlights In the coming months, ClipSpark will expand its live capabilities, enabling real-time detection of quotable moments during webinars and streams, and roll out deeper LMS integrations for automated module packaging. Customers can register for the beta waitlist today. About ClipSpark ClipSpark is the modern way to turn long-form video into shareable knowledge. Using AI, the platform delivers accurate, timestamped captions, concise summaries, and one-click highlight clips that preserve context and credibility. Teams save hours per week, publish more consistently, and build trustworthy libraries that scale across education, media, sales, research, and public sector use cases. Quotes available on request and media kit available at clipspark.ai/press. Media contact Press: press@clipspark.ai Partnerships: partners@clipspark.ai Website: https://clipspark.ai Phone: +1 (415) 555-0137 Forward-looking statements This press release may contain forward-looking statements regarding future product plans and availability, which are subject to change without notice.

P

ClipSpark Debuts Education Suite That Aligns Video to Learning Outcomes with SlideSync Anchors and Outcome Mapper

Imagined Press Article

San Francisco, CA – September 13, 2025 – ClipSpark today introduced an Education Suite designed to help universities, schools, and instructional designers convert lectures and trainings into accessible, outcomes-aligned learning assets at scale. The new capabilities—Outcome Mapper, SlideSync Anchors, Quiz Seedsmith, Standards Packager, Adaptive Chapters, and Mastery Loop—work together to reduce manual rework, improve alignment to accreditation standards, and deliver faster, clearer learning experiences across campus and corporate LMS environments. “Instructional teams want more than transcripts; they want traceability from objectives to the exact minute in a lecture,” said Dr. Lena Porter, VP of Product at ClipSpark. “We built the Education Suite to connect the dots: set measurable outcomes, map them to chapters, pin them to slides, generate assessment-ready quizzes, and continuously improve based on learner analytics.” Outcome Mapper automatically aligns AI-generated chapters to clear, measurable learning objectives using Bloom’s taxonomy. It suggests stronger action verbs, flags gaps or overlaps across modules, and produces an objective-to-timestamp traceability matrix that makes accreditation reviews far less painful. SlideSync Anchors detects slide transitions via OCR and visual fingerprinting, pinning chapters to exact slide titles and numbers and auto-correcting drift between audio and visuals—so learners can navigate confidently across slides, chapters, and timestamps. Quiz Seedsmith expands instructor-provided prompts into well-formed items—multiple choice, true/false, and short-answer—with plausible distractors, targeted feedback, and difficulty levels calibrated to the objectives. Items are tagged to chapters and outcomes and can export to QTI/xAPI or directly to LMS banks, reducing the time from lecture to assessment from weeks to days. “Before ClipSpark, our team maintained a patchwork of tools and manual spreadsheets to keep outcomes, slides, and quizzes in sync,” said Kim Nguyen, Instructional Designer at Western Metro College. “Now we get a package that validates, exports to our LMS without errors, and keeps everything aligned to objectives with full timestamp traceability.” Standards Packager wraps modules for SCORM 1.2/2004, xAPI, and Common Cartridge with manifest validation and auto-fixes for common errors. It includes readiness checks and one-click delivery to Canvas, Moodle, Blackboard, and Cornerstone, reducing upload failures and help-desk tickets. Adaptive Chapters generates micro, standard, and deep-dive variants from the same source while preserving objectives and recalibrating quiz difficulty, so teams can tailor content for different audiences and runtimes without starting over. Mastery Loop closes the feedback loop by ingesting LMS analytics such as completion rates, dwell time, and item difficulty. It then suggests re-chaptering, remediation micro-clips, or objective tweaks, and publishes versioned updates back to the LMS with change logs. Instructors can see what’s working, where learners stall, and how to improve outcomes—without drowning in dashboards. Accessibility and compliance are embedded throughout. ClipSpark’s high-accuracy, timestamped captions and transcripts help teams meet WCAG/ADA requirements, while Policy Blueprints provide prebuilt templates for retention and export controls that can be applied at the course, department, or institution level. GeoFence Exports can enforce data residency for cross-border programs, and Audit Ledger captures a tamper-evident history of access and policy changes for accreditation and audit requests. “Accessibility isn’t a checkbox; it’s a foundation,” said Jordan Patel, Accessibility Compliance Lead at Riverview University. “ClipSpark gives us the accuracy and traceability we need to serve diverse learners and to respond to audits with confidence.” Results from early adopters are encouraging. Institutions report a 60–80% reduction in time spent aligning lectures to outcomes and slides, fewer LMS upload errors, and higher learner engagement with micro and deep-dive chapter variants. Students benefit from timestamped navigation tied to slide titles, making study sessions more targeted and less time-consuming. Availability and pricing The Education Suite is available today for all ClipSpark Pro, Team, and Enterprise plans, with advanced governance features available to Enterprise customers. Campus-wide licensing and volume discounts are offered for higher education and K–12 districts. Interested programs can request a pilot with white-glove onboarding and data migration support. Getting started Instructional teams can import existing slide decks and objective lists, or start from a lecture recording and let ClipSpark propose objectives and chapters for review. Standards Packager runs readiness checks before export, and Mastery Loop begins learning from day one. About ClipSpark ClipSpark helps educators, trainers, and institutions transform long-form video into accessible, outcomes-aligned learning experiences. By combining precise timestamps with clear objectives, slide-aware chapters, and assessment-ready items, ClipSpark reduces manual rework and makes continuous improvement practical for teams of any size. Media contact Press: press@clipspark.ai Education partnerships: edu@clipspark.ai Website: https://clipspark.ai/education Phone: +1 (415) 555-0137 Forward-looking statements This press release may contain forward-looking statements about product features and availability that are subject to change without notice.

P

ClipSpark Introduces Court‑Grade Quote Integrity with HashLock Anchors, Exhibit Forge, and Open Verifier

Imagined Press Article

San Francisco, CA – September 13, 2025 – ClipSpark today unveiled a suite of integrity and verification capabilities that make quotes, captions, and highlight clips defensible under scrutiny. The new tools—HashLock Anchors, Context Halo, Exhibit Forge, Open Verifier, Redaction Shield, and Custody Chain—bind every cited word to its exact audio, preserve surrounding context, and create a verifiable chain of custody from capture to export. Legal teams, regulators, investigative journalists, and organizations in regulated industries can now move faster without sacrificing rigor. “Precision and provenance matter when seconds and words can change outcomes,” said Rohan Mehta, CTO at ClipSpark. “With HashLock Anchors, we bind each quoted word to positional indices and cryptographic hashes that survive transcript edits and media re-encodes. Anyone can verify a quote’s integrity—inside or outside the workspace—without special software.” HashLock Anchors compute per-word fingerprints and align them to the source audio so that any quoted segment can be verified against the original recording. Context Halo automatically attaches a configurable buffer before and after each quote, locking it cryptographically and allowing reviewers to expand with one click. This reduces cherry-pick disputes and speeds approvals by keeping context front-and-center. Exhibit Forge assembles a court-ready bundle in one step: a paginated PDF with quote, speaker, and timestamps; a QR deep link to the exact moment; an authenticated audio snippet; a hash manifest; Bates numbering; and a verifier sheet. What previously took paralegals hours can now be produced in minutes, with fewer opportunities for error. “ClipSpark has changed the way our litigation support team prepares and validates evidence,” said Casey Reynolds, Litigation Support Manager at Whitfield & Rowe LLP. “We can stand behind quotes because they’re bound to the audio. The ability to share a redacted exhibit that still verifies against the original is a big deal for privacy and for negotiations.” Open Verifier provides a public, read-only portal and offline verifier so third parties—opposing counsel, regulators, journalists—can confirm quotes without a login. Redaction Shield supports selective-disclosure hashing using Merkle proofs, enabling teams to redact PII or privileged text while preserving verifiability against the original audio. Custody Chain maintains a quote-level chain of custody from capture to export with signer identities, timestamps, and environment metadata, and it can export a signed ledger alongside each exhibit. For organizations with strict governance requirements, ClipSpark integrates these controls with policy and access layers. ClipGuard Links enable expiring, SSO-gated, single-use links tied to specific users, with dynamic watermarks and instant revocation. Audit Ledger captures a tamper-evident, cryptographically chained history of access, exports, and policy changes, providing one-click audit packs or continuous log streaming to a SIEM. Delegated Approvals introduce scoped admin tiers and time-bound exception workflows, ensuring that export overrides or retention pauses are reviewed by the right approvers with full traceability. “Enterprises need to move quickly without compromising on compliance,” said Sara Valdez, Head of Security and Compliance at ClipSpark. “We’ve combined defensible integrity with pragmatic guardrails so teams can collaborate confidently—inside the firm, with clients, and with regulators.” Use cases extend beyond the courtroom. Investigative reporters can corroborate quotes at scale. Public sector clerks can publish accessible minutes and highlight clips with verifiable provenance. Sales and customer success teams can resolve disputes faster with context-locked excerpts from recorded calls. Research teams can preserve speaker fidelity and reduce misquote risk in qualitative studies. Availability and onboarding HashLock Anchors, Context Halo, and Open Verifier are available today for Pro, Team, and Enterprise plans. Exhibit Forge, Redaction Shield, and Custody Chain are available on Enterprise plans with governance features enabled. ClipSpark offers white-glove onboarding for legal and public sector customers, including policy blueprint setup, user training, and SIEM integrations. About ClipSpark ClipSpark transforms long-form video into accurate captions, concise summaries, and one-click highlights—now with court-grade quote integrity. Built for teams that need speed and confidence, ClipSpark’s verification stack preserves context and proves provenance from first capture to final share. Media contact Press: press@clipspark.ai Legal and public sector: trust@clipspark.ai Website: https://clipspark.ai/trust Phone: +1 (415) 555-0137 Forward-looking statements This press release may contain forward-looking statements about product features and availability that are subject to change without notice.

P

ClipSpark Launches Live Moment Suite to Capture Share‑Ready Highlights in Real Time

Imagined Press Article

San Francisco, CA – September 13, 2025 – ClipSpark today announced the Live Moment Suite, a real-time toolkit that detects quotable spikes during livestreams and virtual events, buffers crucial build-up, and turns signals into shareable clips without leaving chat. The suite—Signal Tuner, Crowd Pulse, BackCapture DVR, Action Pings, Momentum Heatmap, Risk Sentinel, and Speaker Cues—helps marketing, community, and sales teams publish high-signal highlights while the audience is still engaged. “Live content is a goldmine that too often evaporates the minute the event ends,” said Nate Okafor, Head of Live Product at ClipSpark. “We capture what the audience actually cared about, preserve the context that makes it compelling, and let teams publish in the same window where they collaborate.” Signal Tuner lets producers dial in what counts during a live stream with adjustable sensitivity, keyword weighting, and noise suppression. Teams can create role-based profiles—sales, education, legal—to prioritize different triggers and preview markers before they fire. Crowd Pulse fuses audience energy by ingesting chat, reactions, and poll spikes from platforms including YouTube, Twitch, Zoom, and Teams. The system correlates sentiment surges with on-screen moments to surface clips that mirror real engagement. BackCapture DVR continuously buffers the last 30 seconds to 5 minutes so every spike includes build-up, not just the punchline. When a moment hits, ClipSpark auto-stitches pre-roll and post-roll into a clean, branded clip using Smart Trim to remove dead air while preserving meaning and rhythm. Action Pings turn alerts into action with interactive notifications in Slack or Teams: approvers can tag, assign, or publish a clip directly from chat—no tab switching required. “During our last product demo, we had three clips live on social before the Q&A even ended,” said Cara Mitchell, Field Marketing Manager at NimbusWorks. “The heatmap showed exactly where the audience leaned in, and we shipped a recap reel from the heatmap in a single pass.” Momentum Heatmap provides a live timeline with intensity layers for sentiment, keywords, and speaker emphasis. Post-event, teams can jump directly to peaks, compare segments, and export a highlight reel from the heatmap view in minutes. Speaker Cues detects speaker changes, emphasis shifts, and crowd reactions—applause, laughter—to tag likely soundbites as they happen, enabling balanced reels with crisp, attributable quotes. Risk Sentinel protects brand and compliance by catching sensitive terms, PII, profanity, or NDA/industry-specific red flags in real time. ClipSpark can auto-bleep or watermark flagged clips, route them to approvers, and maintain an audit trail for reviews. Together with ClipGuard Links and GeoFence Exports, teams can safely share live moments for external reviews without losing traceability or violating regional controls. The Live Moment Suite integrates with ClipSpark’s broader publishing pipeline. Smart CTAs can be layered onto highlight clips to drive measurable outcomes—subscribe, book demo, download PDF—while UTM AutoTag appends clean attribution to every share destination and syncs to GA4, HubSpot, and Salesforce. Brand Skins ensure every clip ships on-brand across aspect ratios and channels, and Card Packs bundle related clips into a swipeable carousel or sequenced mini-playlist with a single link. “Clips that resonate are clips that reflect the room,” added Okafor. “By combining signal detection, audience correlation, and instant action where teams work, the Live Moment Suite turns ephemeral engagement into durable momentum.” Availability and pricing The Live Moment Suite is available today for Pro, Team, and Enterprise plans. Slack and Teams integrations are included. Enterprise customers can enable advanced risk controls, audit logging, and SSO-gated ClipGuard review links. About ClipSpark ClipSpark uses AI to turn long-form video into accurate, timestamped captions, concise summaries, and one-click highlight clips. With the Live Moment Suite, teams can capture and publish the moments that move audiences while the event is still live—no scrubbing, no stalls, just share-ready impact. Media contact Press: press@clipspark.ai Events and partnerships: live@clipspark.ai Website: https://clipspark.ai/live Phone: +1 (415) 555-0137 Forward-looking statements This press release may contain forward-looking statements about product features and availability that are subject to change without notice.

P

ClipSpark Expands Enterprise Governance with Policy Blueprints, SCIM SmartMap, and GeoFence Exports

Imagined Press Article

San Francisco, CA – September 13, 2025 – ClipSpark today announced new enterprise governance and security capabilities that give IT, security, and compliance teams fine-grained control over how video knowledge is created, shared, and retained. The additions—Policy Blueprints, SCIM SmartMap, GeoFence Exports, ClipGuard Links, Audit Ledger, and Delegated Approvals—help organizations accelerate collaboration while honoring regulatory, regional, and contractual requirements. “Video is exploding across the enterprise, but so are the risks,” said Sara Valdez, Head of Security and Compliance at ClipSpark. “We’ve built controls that are powerful enough for regulated industries yet simple enough that admins can deploy them without writing policies from scratch or slowing teams down.” Policy Blueprints provide prebuilt templates for retention, export controls, and watermarking inspired by frameworks like SOC 2, HIPAA, FINRA, and GDPR. Admins can apply policies at the org, team, or project level; simulate impact before rollout; and get guided suggestions to fix gaps—reducing setup time and audit risk. SCIM SmartMap maps identity attributes and groups to roles via a visual rule builder (for example, if Department = Sales then Export = Denied), previews deltas before syncing, and auto-rolls back on errors to prevent over-permissioning. GeoFence Exports enforces country, region, and IP-based controls on downloads and shares. Admins can block or allow by domain, flag ITAR/EAR content, and honor data residency, stopping non-compliant exports at the source while giving clear, actionable controls. ClipGuard Links create expiring, SSO-gated, single-use links tied to specific users with dynamic, identity-stamped watermarks that include email, time, and IP; access can be revoked instantly from the dashboard, enabling safe external reviews without losing traceability. “ClipSpark’s new governance features let us move at the speed of the business while tightening controls where it counts,” said Aisha Thompson, Director of IT at Helion Health. “Delegated Approvals give our teams a fast path to exceptions with full auditability, and Audit Ledger means we can answer who-accessed-what in seconds.” Audit Ledger captures a tamper-evident, cryptographically chained history of access, exports, and policy changes, with one-click audit packs and log streaming to SIEM platforms. Delegated Approvals introduces scoped admin tiers and time-bound exception workflows, routing requests—like export override or retention pause—to the right approvers with auto-expiry and complete traceability. Combined, these capabilities give CISOs a defensible posture without forcing end users into brittle workarounds. The governance layer integrates with ClipSpark’s core strengths in accuracy, context, and productivity. Accurate, timestamped captions and transcripts support accessibility and internal search. One-click highlight clips and summaries expand shareable output without multiplying risk. When needed, integrity features such as HashLock Anchors and Open Verifier provide quote-level provenance for legal and regulatory uses. Admins can orchestrate broad enablement while reserving stricter workflows for sensitive teams, such as legal, finance, or R&D. “Governance isn’t valuable if it’s invisible to the people who need to follow it,” added Valdez. “We surface just-in-time guidance and approvals inside the creative flow, so work keeps moving and compliance becomes a natural outcome, not an afterthought.” Availability and deployment Policy Blueprints, SCIM SmartMap, and GeoFence Exports are available today on Enterprise plans. ClipGuard Links, Audit Ledger, and Delegated Approvals can be added to Pro and Team plans as governance add-ons. ClipSpark offers implementation support, including policy workshops, identity mapping assistance, and SIEM integration guides. About ClipSpark ClipSpark helps enterprises turn long-form video into accurate captions, concise summaries, and one-click highlight clips—now under strong guardrails. With policy templates, identity-aware permissions, and cryptographic auditability, ClipSpark lets organizations scale video knowledge with speed and confidence. Media contact Press: press@clipspark.ai Enterprise sales: sales@clipspark.ai Website: https://clipspark.ai/enterprise Phone: +1 (415) 555-0137 Forward-looking statements This press release may contain forward-looking statements about product features and availability that are subject to change without notice.

Want More Amazing Product Ideas?

Subscribe to receive a fresh, AI-generated product idea in your inbox every day. It's completely free, and you might just discover your next big thing!

Product team collaborating

Transform ideas into products

Full.CX effortlessly brings product visions to life.

This product was entirely generated using our AI and advanced algorithms. When you upgrade, you'll gain access to detailed product requirements, user personas, and feature specifications just like what you see below.