# Conversation Forks and Clones

Conversation forks create a new persisted conversation from an existing conversation snapshot.

The goal is to let applications branch from prior context without mutating the original conversation. This is useful for retrying a different model, exploring alternative prompts, or continuing from an earlier turn while preserving the original transcript.

## Terminology

`clone` means copy the full source conversation into a new conversation identity.

`fork` means copy the source conversation through a selected turn, then let future turns diverge under the new reference.

The implementation treats clone as a fork whose `through_turn` is the latest copied turn.

## Public Shape

The facade exposes both static and instance-friendly helpers:

```php
$forked = AI::forkConversation('source_ref', 'new_ref', array(
    'through_turn' => null,
    'copy_memory' => true,
    'copy_notes' => true,
    'copy_metadata' => true,
    'provider_continuity' => 'preserve',
));

$forked = AI::provider('gemini')
    ->reference('source_ref')
    ->forkTo('new_ref');
```

References may be strings or `ConversationReference` instances. String references are treated as external references, matching the existing `AI::reference()` behavior.

## Behavior

The target conversation gets a new conversation identity and new persistence rows.

Copied turns keep their original turn numbers so replay and transcript reconstruction remain simple. The next runtime turn on the target conversation is therefore `last_copied_turn + 1`.

Conversation memory is copied by default, including title, summary, metadata, and notes. This can be disabled with `copy_memory` or `copy_notes`.

Conversation metadata is copied by default. The target always receives lineage metadata under `forked_from`, recording source identity, source external reference, copied turn boundary, and fork time.

Assets and provider asset bindings are referenced through copied requests, not duplicated. Provider-specific upload records already represent reusable remote files and should not be cloned into new asset rows for a conversation branch.

## Provider Continuity

OpenAI can continue a previous response chain through `previous_response_id`. A fork may intentionally preserve that provider-native continuity or may scrub it and rely on replayed transcript history.

Supported `provider_continuity` values:

- `preserve`: keep provider response IDs and provider raw payloads.
- `scrub`: remove copied response IDs, `previous_response_id` request options, and provider raw payloads from copied turns.

Gemini replay is transcript-based, so this setting has less effect there.

## Persistence

The first implementation should avoid schema changes. It can load the source conversation through `PersistenceProviderInterface`, create a new `Conversation`, then save it and each copied turn through existing methods.

Lineage initially lives in conversation metadata. First-class columns such as `parent_conversation_id` and `forked_from_turn_number` can be added later if branch discovery becomes a query requirement.

## Test Coverage

Focused coverage should verify:

- a fork receives a new reference and preserves source history through `through_turn`
- the source conversation is not mutated
- memory and notes are copied by default
- memory or notes can be omitted
- `provider_continuity=scrub` removes copied OpenAI response continuity
- saved target turns allow the next runtime turn number to continue after the copied history
