# Agent Production Contract

Sprint: 8.8 — Review Rejection, Revision Flow & Creative Quality Gate

## Core rule

The Dashboard Production Plan is the source of truth.

Jarvis must not start production from chat improvisation. A casual command such as:

```text
mach mal
produziere das nächste Short
Produziere das nächste Short gemäss Dashboard-Produktionsplan.
```

is **not** production approval. The first response must be a detailed concept proposal based on the next Dashboard queue item.

Canonical loop:

```text
Production Plan
→ concept proposal in chat
→ explicit APPROVE_PRODUCTION <queue_item_id>
→ production
→ prepared package
→ dashboard review
```

No upload, no website push, no final/expensive render, and no package writing before explicit production approval.

## Required API flow

### 1. Fetch next Dashboard item

```http
GET /api/agent/production/next
```

Jarvis must read at least:

```text
queue_item_id
title
family
family_id
brief
hook
recommended_reason
script_constraints
visual_constraints
voice_constraints
expected_package_id
expected_package_manifest
production_rules
confirm_command
```

If no item is available, respond clearly:

```text
Kein freigegebenes oder fixiertes Produktions-Item vorhanden.
```

### 2. Mark concept proposed

Before presenting the concept, mark the item as concept-proposed:

```http
POST /api/agent/production/{queue_item_id}/concept-proposed
```

This returns/records the confirmation command:

```text
APPROVE_PRODUCTION <queue_item_id>
```

### 3. Present concept in chat

Jarvis must show the creator a detailed concept before producing anything.

Required chat structure:

```text
Ich habe das nächste Produktions-Item aus dem Dashboard geladen.

Queue item:
...

Arbeitstitel:
...

Content-Family:
...

Warum dieses Video jetzt:
- ...
- ...

Hook:
...

Script-Konzept:
1. ...
2. ...
3. ...

Visuelles Konzept:
...

Voice / Ton:
...

TikTok Caption:
...

TikTok Hashtags:
...

YouTube Title:
...

YouTube Description:
...

Risiken / Dinge, die ich bewusst vermeide:
- keine echten Scam-URLs
- keine echten Telefonnummern
- keine echten Bank-/Kartendaten
- kein Website-Push
- kein Upload ohne Review
- kein finaler teurer Render ohne separate Freigabe, falls relevant

Wenn du dieses Konzept freigibst, bestätige mit:

APPROVE_PRODUCTION <queue_item_id>
```

At this stage Jarvis must not:

- render files
- create voiceover
- write a package
- prepare upload requests
- push website files
- start a final/expensive render

### 4. Wait for explicit approval

Allowed approval formats:

```text
APPROVE_PRODUCTION <queue_item_id>
```

or a clearly equivalent creator response such as:

```text
Ja, dieses Konzept produzieren.
```

Ambiguous/casual text is not enough. If approval is ambiguous, ask for confirmation.

### 5. Approve generation, then mark started

Only after explicit approval:

```http
POST /api/agent/production/{queue_item_id}/approve-generation
```

Then:

```http
POST /api/agent/production/{queue_item_id}/mark-started
```

Important backend invariant:

```text
mark-started must fail unless the item is concept_approved.
```

The backend enforces this with HTTP 409. Agents and UI routes must not bypass this gate.

## Quality-first production gate

`GET /api/agent/production/next` must deliver the active `quality_profile` and mandatory `director_skill`:

```json
{
  "quality_profile": {
    "version": "autoshorts-quality-v1",
    "visual_policy": "...",
    "voice_policy": "...",
    "hook_policy": "...",
    "metadata_policy": "...",
    "safety_policy": "...",
    "render_policy": "...",
    "gates_required": [
      "visual_gate",
      "voice_gate",
      "hook_gate",
      "metadata_gate",
      "safety_gate",
      "package_integrity_gate"
    ]
  },
  "director_skill": {
    "name": "AutoShorts Director Quality v1",
    "doc": "docs/director-production-skill.md",
    "required": true
  }
}
```

Jarvis must read these rules from the Dashboard response for every production run. Memory or chat habit is not enough.

Mandatory Director workflow:

1. Director Visual Plan.
2. 3–5 premium text-free AI styleframes.
3. Styleframe QA.
4. Gianna/voice multi-take QA with transcript comparison.
5. Hook/retention scoring.
6. Metadata/safety/package integrity gates.
7. `quality.overall = passed` before active review.

Hard blockers for real review candidates:

- PowerPoint/template/test-slide look.
- Pure Pillow/deterministic layouts as final visual style.
- Voice-over pronunciation/speech errors.
- Missing quality reports.
- Hook score below 8/10.
- Real logos, URLs, phone numbers, bank/card/IBAN/private data.
- Any failed safety or package integrity gate.

### 6. Produce prepared package

Create the prepared package under:

```text
storage/incoming/<expected_package_id>/
```

Expected files for the first real test:

```text
video.mp4
manifest.json
thumbnail.jpg optional
transcript.txt optional
```

Required manifest shape:

```json
{
  "package_id": "expected package id from dashboard",
  "source": "prepared_package",
  "queue_item_id": "...",
  "family_id": "...",
  "idea_id": null,
  "content_script_id": null,
  "working_title": "...",
  "language": "en",
  "series": "...",
  "suggested_tiktok_caption": "...",
  "suggested_youtube_title": "...",
  "suggested_youtube_description": "...",
  "suggested_hashtags": ["#onlinesafety", "#cybersecurity"],
  "script": "...",
  "hook": "...",
  "production_notes": "...",
  "disclosure": {
    "synthetic_media": true,
    "commercial_content": false
  },
  "quality": {
    "visual_gate": "passed",
    "voice_gate": "passed",
    "hook_gate": "passed",
    "metadata_gate": "passed",
    "safety_gate": "passed",
    "package_integrity_gate": "passed",
    "overall": "passed"
  },
  "status": "ready_for_review"
}
```

Required quality files in the package:

```text
production_report.json
quality_report.json
voice_qa.json
visual_qa.json
```

For `source=prepared_package` with `queue_item_id`, the importer must not set `ready_for_review` unless `quality.overall = passed`. Missing/failed quality becomes `needs_internal_fix` / `quality_failed` and stays out of active Review.

### 7. Import and mark ready for review

Scan/import:

```http
POST /api/imports/scan
```

Attach package:

```http
POST /api/agent/production/{queue_item_id}/attach-package
```

Payload:

```json
{
  "package_id": "<expected_package_id>",
  "package_path": "storage/incoming/<expected_package_id>",
  "manifest_path": "storage/incoming/<expected_package_id>/manifest.json",
  "video_asset_id": "optional-after-import"
}
```

Mark ready for dashboard review:

```http
POST /api/agent/production/{queue_item_id}/mark-ready-for-review
```

Payload:

```json
{
  "package_id": "<expected_package_id>",
  "video_asset_id": "..."
}
```

Target state:

```text
Video appears in /videos
Video appears in the Review Queue
Review page can play the video
TikTok manual export is available
YouTube private upload via Existing Jarvis uploader can be approved later
ProductionQueueItem status is in_review
```

## Safe legacy route behavior

The legacy route:

```http
POST /api/production-queue/{item_id}/send-to-production
```

must never directly start production. It may only move the item to:

```text
concept_proposed
```

or return HTTP 409 if the item lacks concept approval. The only allowed production start is:

```text
concept_proposed
→ concept_approved via approve-generation
→ producing via mark-started
```

## Expected `GET /api/agent/production/next` response

```json
{
  "queue_item_id": "...",
  "family": "Everyday Red Flags",
  "family_id": "...",
  "idea": "...",
  "idea_id": "...",
  "content_script_id": "...",
  "title": "Delivery fee traps: the courier chatbot pressure trick",
  "brief": "...",
  "hook": "...",
  "script_constraints": "...",
  "visual_constraints": "...",
  "voice_constraints": "...",
  "recommended_reason": [
    "..."
  ],
  "expected_package_id": "package_<queue_item_id_prefix>",
  "expected_package_manifest": "storage/incoming/package_<queue_item_id_prefix>/manifest.json",
  "confirm_command": "APPROVE_PRODUCTION <queue_item_id>",
  "requires_concept_confirmation": true,
  "next_required_action": "propose_concept_then_wait_for_APPROVE_PRODUCTION",
  "production_rules": {
    "no_final_wan_render_without_approval": true,
    "test_preview_allowed": false,
    "renderer_owned_text": true,
    "no_unreviewed_upload": true,
    "quality_report_required": true,
    "ready_for_review_requires_quality_passed": true
  },
  "quality_profile": {
    "version": "autoshorts-quality-v1",
    "gates_required": ["visual_gate", "voice_gate", "hook_gate", "metadata_gate", "safety_gate", "package_integrity_gate"]
  },
  "director_skill": {
    "name": "AutoShorts Director Quality v1",
    "doc": "docs/director-production-skill.md",
    "required": true
  }
}
```

## Status transitions

Concept-gated and quality-gated loop:

```text
suggested / approved_next / locked_next
→ concept_proposed
→ concept_approved
→ producing
→ package_ready only if quality.overall = passed
→ in_review
```

Quality failure loop:

```text
producing
→ needs_internal_fix / quality_failed
```

Review rejection/revision loop:

```text
ready_for_review / in_review
→ rejected       (Reject video; drafts rejected; removed from active review)
→ needs_changes  (Request changes; RevisionRequest open; not normal review)
```

Review/upload loop after creator review:

```text
ready_for_review / in_review
→ upload request approved by creator
→ waiting_for_executor / sent_to_executor
→ uploaded_private / completed
```

A completed UploadRequest without a real `youtube_video_id` is a mechanical status test only. A real upload result must be imported via audit or completed with a real ID after explicit creator approval.

## Upload rules

During production Jarvis must not:

- perform TikTok upload
- create TikTok mock/draft API flows
- push or merge website files
- publicly upload to YouTube
- privately upload to YouTube before dashboard review approval
- invent YouTube IDs

TikTok remains manual:

- download MP4 in dashboard
- copy caption
- copy hashtags
- upload manually in TikTok
- optionally mark manually posted later

Existing Jarvis YouTube uploader remains the real private-upload executor, but only after a creator-approved UploadRequest or explicit creator upload approval.

## Failure cases

- No next item: do not produce; report `Kein freigegebenes oder fixiertes Produktions-Item vorhanden.`
- Concept not approved: do not call `mark-started`; do not write package.
- `mark-started` returns 409: stop and report that concept approval is missing.
- Package generation fails: call `mark-failed` with a concise error.
- Import fails: leave package in incoming, call `mark-failed`, do not upload.
- Review not approved: do not create upload request.
- Upload audit missing: keep UploadRequest waiting/sent; do not invent YouTube IDs.

## Jarvis must never automatically do these

- No TikTok actions.
- No website push.
- No deletion or merge of pending website files.
- No real YouTube upload without explicit creator approval.
- No final/expensive render without explicit creator approval.
- No secrets/tokens in manifests, outbox JSON, logs, or chat responses.
- No public/private video link exposure on the website unless link allowance is explicit and publication is approved.
