Skip to content

fix(log): a fork mints its own executionId and records forkedFrom - #178

Open
davidkpiano wants to merge 3 commits into
nextfrom
davidkpiano/fork-lineage
Open

davidkpiano wants to merge 3 commits into
nextfrom
davidkpiano/fork-lineage

Conversation

@davidkpiano

@davidkpiano davidkpiano commented Oct 24, 2026 •

Copy link
Copy Markdown
Member

A fork kept its parent's executionId, so a forked thread's calls got the same info.callKey as the parent's calls at the same site. An executor cache keyed on callKey could hand the fork its parent's result.

Change

  • forkEventLog gives the fork's init entry a fresh metadata.executionId and metadata.forkedFrom: { executionId, logIndex }. Every other entry is copied as is.
  • store.fork goes through forkEventLog: the in-memory store, the Durable Object store in examples/cloudflare-agent-host, and the file store in examples/code-review-loop.
  • assertEventLogStoreConformance has a new case: two forks of one thread each get their own id, forkedFrom names the parent and cutoff, later entries are unchanged, and the source is untouched. Its fixtures now start with a real init entry.

Behavior changes

  • Custom stores: a fork that copies rows verbatim now fails the conformance suite. The changeset says so.
  • Resuming a fork from a parent snapshot: the snapshot's agentMeta.logId no longer matches, so the resume folds the fork's log instead of taking the fast path.
  • Docs:
    • hosts.md used to say a fork could reuse the parent's cached results by key; it now says a fork's keys never match its parent's.
    • The "cache on callKey plus a fingerprint" advice stays. A version bridge still keeps the lineage id, so a migrated machine can ask something else under the same key.
    • The createPolicyDecider thread-hash rationale is reworded to match.

Verification

  • New runtime test: fork a stored thread, resume parent and fork with the same event. Each call key starts with its own thread's execution id. It fails on next's forkEventLog.
  • vitest --run: 139 files, 1665 tests pass. typecheck, lint, format:check, knip, docs:check, typecheck:example-packages, and test:cloudflare (the DO store runs the conformance suite) pass.

Summary by CodeRabbit

  • New Features

    • Forked conversations now receive a distinct execution lineage, with metadata linking them to the parent and the point where they branched. Their remaining history is preserved, and calls are distinguished from those in the parent.
    • A parent snapshot can be used to resume a fork through a version bridge only while the fork remains at its branching point. Supplied event history must match the stored conversation’s lineage.
  • Documentation

    • Clarified how lineage, request matching, policy threads, and custom event-log stores behave across forks and version bridges.

forkEventLog and store.fork gave the fork its parent's executionId, so a
forked thread's calls got the parent's callKeys and a cache keyed on them
could return the parent's result. The fork's init entry now gets a fresh
executionId and forkedFrom: { executionId, logIndex }. The in-memory,
Durable Object and file stores fork through forkEventLog, and the
conformance suite checks the lineage.
@changeset-bot

changeset-bot Bot commented Oct 24, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 337efa8

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 6 packages
Name Type
@statelyai/agent Patch
@statelyai/agent-demo Patch
@statelyai/example-next-host Patch
@statelyai/example-tanstack-ai-stream Patch
@statelyai/example-cloudflare-agent-host Patch
@statelyai/example-cloudflare-workers-ai-host Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai

coderabbitai Bot commented Oct 24, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review.

Recent review info
Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: c691ab32-9e87-4cd2-970c-01b10895df60
Commits

Reviewing files that changed from the base of the PR and between 95692cb and 337efa8.

Files selected for processing: 4
  • .changeset/fork-lineage.md
  • docs/event-log.md
  • src/run-agent.test.ts
  • src/run-agent.ts
Files skipped from review as they are similar to previous changes: 1
  • .changeset/fork-lineage.md

Included review availability: This review used your included allowance. Your plan provides up to 2 included reviews per hour; 0 remain after this review.

Walkthrough

Forked logs now receive a fresh execution ID on the init entry and record the parent execution ID, when available, and the cutoff index. Stores use the fork transformation. Runtime checks validate lineage when matching stored threads and resuming snapshots.

Changes: Fork execution lineage

Layer / File(s) Summary
Fork log lineage
src/event-log.ts, src/event-log.test.ts
forkEventLog assigns a fresh execution ID to the fork’s init entry and adds forkedFrom metadata. Other selected entries remain unchanged. The test checks the metadata and verifies that the source log is unchanged.
Store integration and conformance
src/event-log-store.ts, src/event-log-store-conformance.ts, src/event-log-store.test.ts, examples/cloudflare-agent-host/event-log-store.ts, examples/code-review-loop/file-store.ts, .changeset/fork-lineage.md, docs/event-log.md
The stores use forkEventLog to create fork prefixes. Conformance checks verify lineage metadata, copied entries, and source preservation. The changeset and event-log documentation describe the store contract and snapshot-resume behavior.
Runtime lineage and resume validation
src/run-agent.ts, src/run-agent.test.ts, src/policy-decider.ts, src/text-logic.ts, docs/decisions.md, docs/hosts.md
Stored-thread matching checks init-entry execution IDs. Version bridging accepts a parent snapshot only while the fork remains at its cutoff. Tests and documentation cover fork-specific call keys, version bridges, and request-fingerprint checks.

Priority: Normal

Estimated code review effort: 3 (Moderate) | ~25 minutes

Change: Bug fix

Sequence Diagram(s)

sequenceDiagram
  participant EventLogStore
  participant forkEventLog
  participant runAgent
  EventLogStore->>forkEventLog: source prefix and cutoff
  forkEventLog-->>EventLogStore: prefix with new init lineage
  EventLogStore->>runAgent: forked events and parent snapshot
  runAgent->>runAgent: validate parent snapshot against fork cutoff
Loading

Possibly related PRs

  • statelyai/agent#174: Both PRs change event-log resume validation and snapshot compatibility.
  • statelyai/agent#173: Both PRs address policy thread identity across call keys and changed policy input.

Suggested reviewers: claude

Merge Risk: Minimal · up to 337ef

No merge-blocking issue is established; this change is mergeable after normal checks.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 61.54% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 13 functions across 11 files. (2 skipped:… Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly and concisely describes the main change: forked logs receive a new executionId and record forkedFrom metadata.
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Docstring Coverage

Explanation

Docstring coverage is 61.54% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 13 functions across 11 files. (2 skipped: 2 unsupported.)

Resolution

Write docstrings for the functions missing them to satisfy the coverage threshold.

Finishing Touches: 💡 1
📝 Generate docstrings: 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

coderabbitai[bot]

This comment was marked as resolved.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 2 potential issues.

Devin Review

Comment thread src/event-log.ts
Comment thread src/event-log.ts
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