Skip to content

feat(pair): keep the executor in step with its lead - #632

Merged
rynfar merged 6 commits into
pylonfrom
feat/pair-lifecycle
Sep 18, 2026
Merged

rynfar merged 6 commits into
pylonfrom
feat/pair-lifecycle

Conversation

@rynfar

@rynfar rynfar commented Sep 18, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

A pair executor is an ordinary thread, so nothing ties its lifecycle to its lead. Archive or delete a lead and its executor is left behind. Rewind a lead while its executor is mid-turn and the executor keeps editing the worktree they share, on top of the restored files. And the idle-session reaper stops an executor after thirty minutes even while its lead is mid-turn and about to brief it again.

What this adds

  • PairLifecycleReactor, a sidecar over domain events that dispatches only existing commands. Archiving, settling, or deleting a lead does the same to its executor, including an executor that was archived when the pair was turned off. An executor's own lifecycle never echoes back, because archiving it is how a user turns a pair off, and unarchiving a lead does not turn a pair back on. Command ids are derived from the causing event, so a replayed event is absorbed by the receipt store. It reads no settings: following a lead is cleanup and keeps working after delegation is turned off.
  • Stop on rewind. A rewind of the lead is not blocked, since that would mean changing rewind admission in the decider. The reactor interrupts a running executor the moment thread.checkpoint-revert-requested is seen. The executor may still write for a moment before the interrupt lands.
  • Reaper rule. ProviderSessionReaper skips a pair executor while its lead's session is starting or running. A fan-out child is reaped as before.
  • Test-first lead protocol. The text a paired lead receives now makes test-first the method rather than a suggestion: write the contract and failing tests, confirm they fail for the right reason, commit them, brief the executor to make them pass without editing them, ask it for code only, then confirm the tests are unchanged and re-run the checks. This is how every phase since 1a was built.

Not covered

  • A reset (a fresh executor conversation with a handoff summary). Nothing in Pylon drops a session's resume cursor on purpose today; it needs a small core command of its own.
  • Prime Agent's own subagent depth is still not held while paired.
  • The rewind control is not disabled in the UI while the executor runs. That belongs with the Pair panel.
  • No live provider run.

Verification

Run independently by the lead in the executor's worktree:

  • pairLifecycle.logic, PairLifecycleReactor, OrchestrationReactor, serverRuntimeStartup, ProviderSessionReaper, DelegationFollowThroughReactor, ThreadSettlementReactor, and the pair toolkit: 115 tests passed. After the protocol rewrite, RuntimeInstructions and the pair handlers: 45 passed.
  • vp run -F t3 typecheck: exit 0. vp run knip:check: clean.
  • The contract and 13 tests were written by the lead first; 12 failed against stubs and one negative test passed, as intended. The three lead-owned test files are byte-identical after implementation (blob hashes checked).
  • Untouched: decider.ts, projector.ts, migrations, packages/contracts, ws.ts, CheckpointReactor.ts.

Part of #622.

Contract, tests, protocol text, docs, and review by Claude Fable 5.1 in Claude Code; implementation by Gemini 3.8 Flash (High) in Antigravity, as a Pylon delegated child.


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

@vercel

vercel Bot commented Sep 18, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
pylon-marketing Ready Ready Preview Sep 18, 2026 3:51pm UTC

@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:L labels Sep 18, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

Provider Metric Main baseline This PR Impact PR ceiling
Codex Total thread wire 13.9 KiB 14.0 KiB +71 B (+0.5%) 15.1 KiB ✅
Codex Thread snapshot wire 7.2 KiB 7.2 KiB +7 B (+0.1%) 7.3 KiB ✅
Codex Live turn WebSocket wire 6.7 KiB 6.7 KiB +64 B (+0.9%) 7.8 KiB ✅
Codex Live turn WebSocket decoded 58.0 KiB 58.0 KiB +44 B (+0.1%) 66.4 KiB ✅
Codex Live turn messages 8 9 +1 (+12.5%) 21 ✅
Claude Total thread wire 13.9 KiB 14.0 KiB +49 B (+0.3%) 15.1 KiB ✅
Claude Thread snapshot wire 7.2 KiB 7.2 KiB +3 B (+0.0%) 7.3 KiB ✅
Claude Live turn WebSocket wire 6.7 KiB 6.7 KiB +46 B (+0.7%) 7.8 KiB ✅
Claude Live turn WebSocket decoded 58.8 KiB 58.9 KiB +44 B (+0.1%) 66.4 KiB ✅
Claude Live turn messages 8 9 +1 (+12.5%) 21 ✅

Baseline: 43c076a · PR result: 9fa8cfc · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 115.6 KiB
  • Claude decoded thread snapshot: 116.3 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

@rynfar
rynfar merged commit dd7189c into pylon Sep 18, 2026
19 checks passed
@rynfar
rynfar deleted the feat/pair-lifecycle branch September 18, 2026 16:00

This branch was successfully deployed

1 active deployment
Preview — 9fa8cfc0 Deployed Sep 18, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant