Skip to content

feat(api): execution timeline + fork-from — time-travel operations on snapshot state#67

Merged
ovasylenko merged 1 commit into
mainfrom
feat/timeline-fork
Jun 10, 2026
Merged

feat(api): execution timeline + fork-from — time-travel operations on snapshot state#67
ovasylenko merged 1 commit into
mainfrom
feat/timeline-fork

Conversation

@ovasylenko

Copy link
Copy Markdown
Contributor

Summary

Strategic Bet B from docs/FEATURE_OPPORTUNITIES.md: because state-at-every-step is data (snapshots, not an event log), time travel is CRUD. Complements the already-shipped resume-from-block (#59).

  • GET /instances/{id}/timeline — chronological state-at-every-step: {block_id, attempt, completed_at, output, output_ref, is_sentinel} with sentinels flagged (not hidden), instance summary, and state transitions from the audit log. ?limit= (default 200, max 1000), ?offset=, ?include_outputs=false.
  • POST /instances/{id}/fork — clone a production instance into a sandbox: same sequence/tenant/namespace, source context + optional shallow patch, pre-fork block outputs copied so earlier steps don't re-run, dry_run defaults to true so forks can't re-fire side effects unless asked. Metadata records {forked_from, forked_at_block}; concurrency/idempotency keys deliberately dropped so sandboxes don't contend with production slots. Allowed from any source state; source untouched.
  • Artifact-backed outputs can't be shared across instances (keys are instance-prefixed and ownership-checked), so the fork copies inline outputs only — any top-level block whose latest snapshot isn't inline goes to rerun_blocks at composite granularity. Documented in module docs.
  • New storage methods get_outputs_page + copy_block_outputs in both backends + encrypting wrapper; block-order helpers shared with resume-from (no duplication).

Tests

13 API e2e (ordering, sentinels, pagination, fork copy/patch/dry-run/metadata, artifact→rerun set, tenant isolation, error cases) + 4 storage tests + 1 engine e2e through real ticks (forked run: pre-fork block did NOT re-execute, patched context visible, source untouched). 2779 passed across the 3 crates. fmt/clippy/doc gates clean.

🤖 Generated with Claude Code

… snapshot state

GET /instances/{id}/timeline: flat chronological complement of the
execution tree — one entry per block_outputs row in execution order with
sentinels flagged (not hidden), plus instance-level summary (current
state/context) and recorded state transitions from the audit log.
Paginated (default 200, max 1000); ?include_outputs=false returns
metadata only.

POST /instances/{id}/fork: clone an instance into a sandbox that resumes
from an arbitrary top-level block. Copies inline pre-fork block outputs
onto a new Scheduled instance (optional context patch, dry-run by
default, provenance in metadata); artifact-backed/externalized outputs
are instance-scoped, so their blocks go to the re-run set instead of
being copied. Source instance is never touched, so forking is allowed
from any source state.

Storage: OutputStore::get_outputs_page + OutputStore::copy_block_outputs
on both backends and the encrypting wrapper (pass-through — outputs are
not field-encrypted).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@ovasylenko ovasylenko merged commit 3afcff2 into main Jun 10, 2026
13 of 14 checks passed
@ovasylenko ovasylenko deleted the feat/timeline-fork branch June 10, 2026 10:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant