Skip to content

fix(app): preserve v2 retry and stop reliability - #4590

Merged
reachjalil merged 4 commits into
devfrom
fix/v2-run-lifecycle
Sep 8, 2026
Merged

fix(app): preserve v2 retry and stop reliability#4590
reachjalil merged 4 commits into
devfrom
fix/v2-run-lifecycle

Conversation

@reachjalil

@reachjalil reachjalil commented Sep 7, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Preserve native v2 retry attempt, message, and next-at across independent active-session polls. Clear retry on progress or terminal observations, never elapsed time alone.
  • Route conversation Stop through the selected engine: the existing v1 client or the native v2 adapter. Preserve the actual interruption acknowledgement.
  • Distinguish v2 success from user interruption, shutdown, supersession, and idle with unknown outcome. Durable sequence ordering protects successor executions.
  • Protect shared permission settlement and snapshots against stale reads, and consume terminal tracking before listeners can admit queued work. Native terminal/reconnect permission reconciliation is v2-specific.

Current Verification: Incomplete

Head: d52e5dd
Base: 7874bf9 (dev)

Rebased onto current dev and resolved two test conflicts by retaining both the newly merged v1/v2 scoped-permission hydration coverage and this lifecycle coverage. No assertions were removed or weakened. All four rebased commits have verified signatures.

Passed on this head:

  • pnpm --dir apps/app exec bun test --isolate tests/opencode-v2-adapter.test.ts tests/session-sync-run-status.test.ts tests/session-sync-permissions.test.ts: exit 0; 121 passed, 0 failed, 0 skipped; 657 assertions. Includes v1/v2 permission hydration, native v2 lifecycle, and shared status/permission regression coverage.
  • pnpm --dir apps/app typecheck: exit 0.
  • git diff --check origin/dev...HEAD: exit 0.

Not run on this head:

  • OPENWORK_EVAL_ENGINE=v1 pnpm evals:e2e parent-child-permission-approval
  • OPENWORK_EVAL_ENGINE=v2 pnpm evals:e2e parent-child-permission-approval

The CLI placement resolver reports placement: daytona (daytona CLI authenticated). These cold-boot journeys provision cloud resources; execution is pending approval for that resource usage. No local lane override was used. This is an execution-authorization blocker, not a failed product assertion. Both exact-head journey runs and their published evidence are required before declaring merge readiness.

The existing evidence comment at cf14cd8 is historical v2 evidence only and does not validate this rebased head. It also does not establish v1 journey coverage.

Scope And Limits

Automatic task resumption after desktop restart is not implemented here. A separate follow-up must support both engines using durable OpenWork-owned recovery intent, explicit Stop/approval/completion exclusions, engine-specific reconciliation, and bounded staggered starts. Live shutdown/restart and supersession remain outside the current journey proof; focused tests cover their lifecycle handling.

No merge, release, or deployment was performed.

@vercel

vercel Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

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

Project Deployment Actions Updated
openwork-app Ready Ready Preview Sep 8, 2026 7:26pm UTC
openwork-den Ready Ready Preview Sep 8, 2026 7:26pm UTC
openwork-diagnostics Ready Ready Preview Sep 8, 2026 7:26pm UTC
openwork-landing Ready Ready Preview, v0 Sep 8, 2026 7:26pm UTC

diff-warden[bot]
diff-warden Bot previously approved these changes Sep 7, 2026

@diff-warden diff-warden 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.

Warden security clearance: clear. No blocking findings (security or desktop↔den sync) in this diff (cf14cd8c7bf86a3a04c7d7fbc35ec9d9ecb6b61a). Automated clearance satisfies the required-review gate only — a human still reviews and merges. Analysis run

@reachjalil

reachjalil commented Sep 7, 2026

Copy link
Copy Markdown
Collaborator Author

Test evidence — a-parent-task-surfaces-and-resolves-its-child-session-permission-request — ✅ passed

SHA cf14cd8 · engine v2

0/1 screenshots passed · 0 expectations passed · 0 failed · 0 pending

screenshots not attached (gh < 2.99; run brew upgrade gh)

[world] desktop(daytona) · workspace(/tmp/openwork-workspace-spec-1788739994788) · session("New task") · [seed:raw] evalIn()
[user] see(text=/Needs permission/, timeoutMs=30000) · see(text=/Requested by Investigate the deployment failure/) · see(text=/git status --short --branch/) · see(Deny) · see(Allow once) · see(Allow for session)
[probe:raw] [probe:raw] eval()
[user] screenshot · Allow once · click(Allow once) · notSee(text=/Requested by Investigate the deployment failure/) · notSee(text=/Needs permission/)
[probe:raw] [probe:raw] eval()
steps 1 ✅ The parent exposes the child request (2.1s) · 2 ✅ Approving clears the blocked state (18.8s)
verdict passed · 9 user observations (see ×6, screenshot ×1, notSee ×2) · 2 probes · steps 2/2

⚪ UNVALIDATED — 1. a-parent-task-surfaces-and-resolves-its-child-session-permission-request artifact 1

  • UNVALIDATED — no visual expectations recorded.

Test run created 2026-09-07T00:11:31.633Z · Source: evals/results/test-runs/2026-09-07T00-11-31-633Z-a-parent-task-surfaces-and-resolves-its-child-session-permission-request/test-run.json · Repro: pnpm --dir evals artifacts:publish -- --pr 4590 --test-run 2026-09-07T00-11-31-633Z-a-parent-task-surfaces-and-resolves-its-child-session-permission-request

Test evidence — retry-recovery-and-stopping-a-permission-leave-other-requests-and-fresh-work-int — ✅ passed

SHA cf14cd8 · engine v2

0/1 screenshots passed · 0 expectations passed · 0 failed · 0 pending

screenshots not attached (gh < 2.99; run brew upgrade gh)

[world] desktop(daytona) · workspace(/tmp/openwork-workspace-spec-1788740151164) · session("New task") · [seed:raw] evalIn() · mock(mcp) · den(daytona) · desktop(as admin) · workspace(/tmp/openwork-permission-stop-recovery-1788740403838) · [seed:raw] evalIn() ×4 · session("Stop permission task") · session("Keep permission task")
[user] type(composer, "Prepare the retry reliability summary") · press(Enter) · see(text=/Rate limited for lifecycle verification/, timeoutMs=45000)
[probe] desktopApi(GET /workspace/ws_9dc06c67a259/opencode2/api/session/active)
[user] see(text=/Rate limited for lifecycle verification/)
[probe] desktopApi(GET /workspace/ws_9dc06c67a259/opencode2/api/session/active)
[user] see(text=/Rate limited for lifecycle verification/)
[probe] desktopApi(GET /workspace/ws_9dc06c67a259/opencode2/api/session/active)
[user] see(text=/Rate limited for lifecycle verification/) · see(text=Retry recovery finished., timeoutMs=45000) · notSee(text=/Rate limited for lifecycle verification/) · type(composer, "Inspect the other permission workspace") · press(Enter) · see(text=printf OTHER_PERMISSION_WITNESS, timeoutMs=45000)
[probe] desktopApi(GET /workspace/ws_9dc06c67a259/opencode2/api/session/ses_f86c3632effewvctFMtSdzFjdU/permission) · eventually(the unrelated approval is pending)
[user] text=Stop permission task · click(text=Stop permission task)
[probe] hash · eventually(the intended conversation is selected)
[user] type(composer, "Inspect the stopped permission workspace") · press(Enter) · see(text=printf STOP_PERMISSION_WITNESS, timeoutMs=45000)
[probe] desktopApi(GET /workspace/ws_9dc06c67a259/opencode2/api/session/ses_f86c36881ffeMcO3BAP4o2qAue/permission) · desktopApi(GET /workspace/ws_9dc06c67a259/opencode2/api/session/ses_f86c3632effewvctFMtSdzFjdU/permission)
[user] label=Stop · click(label=Stop)
[probe] desktopApi(GET /workspace/ws_9dc06c67a259/opencode2/api/session/ses_f86c36881ffeMcO3BAP4o2qAue/permission) · eventually(native interruption cleanup removes the pending permission)
[user] notSee(Allow once) · notSee(label=Stop)
[probe] desktopApi(GET /workspace/ws_9dc06c67a259/opencode2/api/session/ses_f86c36881ffeMcO3BAP4o2qAue) · desktopApi(GET /workspace/ws_9dc06c67a259/opencode2/api/session/ses_f86c3632effewvctFMtSdzFjdU/permission)
[user] reload · see(composer, editable, timeoutMs=45000) · notSee(Allow once)
[probe] desktopApi(GET /workspace/ws_9dc06c67a259/opencode2/api/session/ses_f86c3632effewvctFMtSdzFjdU/permission)
[user] type(composer, "Continue with a fresh summary instead") · press(Enter) · see(text=Fresh work finished after stop., timeoutMs=45000) · text=Keep permission task · click(text=Keep permission task)
[probe] hash · eventually(the intended conversation is selected)
[user] see(Allow once)
[probe] desktopApi(GET /workspace/ws_9dc06c67a259/opencode2/api/session/ses_f86c3632effewvctFMtSdzFjdU/permission)
[user] Allow once · click(Allow once) · see(text=Permission work finished., timeoutMs=45000) · notSee(Allow once)
[probe] desktopApi(GET /workspace/ws_9dc06c67a259/opencode2/api/session/ses_f86c36881ffeMcO3BAP4o2qAue/permission)
[user] screenshot
steps 1 ✅ a native retry survives active polling and then recovers (10.4s) · 2 ✅ two conversations own separate real approvals (5.7s) · 3 ✅ Stop removes its cancelled approval without a permission reply and preserves the other session (24.1s) · 4 ✅ fresh work completes once and the unrelated approval remains answerable (8.2s)
verdict passed · 17 user observations (see ×11, notSee ×5, screenshot ×1) · 18 probes · steps 4/4

⚪ UNVALIDATED — 1. retry-recovery-and-stopping-a-permission-leave-other-requests-and-fresh-work-int artifact 1

  • UNVALIDATED — no visual expectations recorded.

Test run created 2026-09-07T00:14:10.491Z · Source: evals/results/test-runs/2026-09-07T00-14-10-490Z-retry-recovery-and-stopping-a-permission-leave-other-requests-and-fresh-work-int/test-run.json · Repro: pnpm --dir evals artifacts:publish -- --pr 4590 --test-run 2026-09-07T00-14-10-490Z-retry-recovery-and-stopping-a-permission-leave-other-requests-and-fresh-work-int

Test evidence — a-parent-answers-its-real-child-question-without-settling-an-unrelated-root-ques — ✅ passed

SHA cf14cd8 · engine v2

0/2 screenshots passed · 0 expectations passed · 0 failed · 0 pending

screenshots not attached (gh < 2.99; run brew upgrade gh)

[world] desktop(daytona) · workspace(/tmp/openwork-workspace-spec-1788740566872) · session("New task") · [seed:raw] evalIn() · mock(mcp) · den(daytona) · desktop(as admin) · workspace(/tmp/openwork-permission-stop-recovery-1788740842042) · [seed:raw] evalIn() ×4 · session("Stop permission task") · session("Keep permission task") · mock(mcp) · den(daytona) · desktop(as admin) · workspace(/tmp/openwork-delegated-question-handoff-1788741090017) · [seed:raw] evalIn() ×4 · session("Delegated question parent") · session("Unrelated question root")
[user] type(composer, "Help me choose the unrelated task format") · press(Enter) · see(text=Which format should the unrelated task use?, timeoutMs=45000)
[probe] desktopApi(GET /workspace/ws_3364c24dafcd/opencode2/api/form/request) · eventually(the unrelated root owns a real question request) · desktopApi(GET /workspace/ws_3364c24dafcd/opencode2/api/session/ses_f86b8e080ffeABzd5eYNbYkAo3)
[user] text=Delegated question parent · click(text=Delegated question parent)
[probe] hash · eventually(the requested root conversation is selected)
[user] notSee(text=Which format should the unrelated task use?) · type(composer, "Delegate choosing the task format, then report the result.") · press(Enter)
[probe] desktopApi(GET /workspace/ws_3364c24dafcd/opencode2/api/form/request) ×3 · eventually(the real subagent asks its question) · desktopApi(GET /workspace/ws_3364c24dafcd/opencode2/api/session/ses_f86b8ae9cffegPhsMiuaWKkq6m) · desktopApi(GET /workspace/ws_3364c24dafcd/opencode2/api/session/ses_f86b8e770ffex8sBoi2dmHg118) · desktopApi(GET /workspace/ws_3364c24dafcd/opencode2/api/session/ses_f86b8e080ffeABzd5eYNbYkAo3)
[user] see(text=Which format should the child task use?, timeoutMs=30000) · notSee(text=Which format should the unrelated task use?) · notSee(label=/^Unrelated outline/)
[probe] hash · desktopApi(GET /workspace/ws_3364c24dafcd/opencode2/api/session/ses_f86b8ae9cffegPhsMiuaWKkq6m/context)
[user] reload · see(text=Which format should the child task use?, timeoutMs=45000)
[probe] hash · desktopApi(GET /workspace/ws_3364c24dafcd/opencode2/api/form/request)
[user] notSee(text=Which format should the unrelated task use?) · screenshot · label=/^Child checklist/ · click(label=/^Child checklist/)
[probe] desktopApi(GET /workspace/ws_3364c24dafcd/opencode2/api/form/request) · eventually(only the original child request is settled) · desktopApi(GET /workspace/ws_3364c24dafcd/opencode2/api/session/ses_f86b8ae9cffegPhsMiuaWKkq6m/form/frm_07947548e001blBlk0CTI1XL5Y/state) · desktopApi(GET /workspace/ws_3364c24dafcd/opencode2/api/session/ses_f86b8e080ffeABzd5eYNbYkAo3/form/frm_079473148001PS50yjmpk5XV5e/state) · desktopApi(GET /workspace/ws_3364c24dafcd/opencode2/api/session/ses_f86b8ae9cffegPhsMiuaWKkq6m/context) · eventually(question settles and its session returns the actual answer) · desktopApi(GET /workspace/ws_3364c24dafcd/opencode2/api/session/ses_f86b8ae9cffegPhsMiuaWKkq6m) · eventually(the native session records successful completion) · desktopApi(GET /workspace/ws_3364c24dafcd/opencode2/api/session/ses_f86b8e770ffex8sBoi2dmHg118/context) · eventually(subagent settles and its session returns the actual answer) · desktopApi(GET /workspace/ws_3364c24dafcd/opencode2/api/session/ses_f86b8e770ffex8sBoi2dmHg118) · eventually(the native session records successful completion)
[user] see(text=/User has answered your questions:.="Child checklist"/) · notSee(label=/^Child checklist/)
[probe] hash · desktopApi(GET /workspace/ws_3364c24dafcd/opencode2/api/form/request) · desktopApi(GET /workspace/ws_3364c24dafcd/opencode2/api/session/ses_f86b8e080ffeABzd5eYNbYkAo3/context)
[user] text=Unrelated question root · click(text=Unrelated question root)
[probe] hash · eventually(the requested root conversation is selected)
[user] see(text=Which format should the unrelated task use?) · notSee(text=Which format should the child task use?) · label=/^Unrelated outline/ · click(label=/^Unrelated outline/)
[probe] desktopApi(GET /workspace/ws_3364c24dafcd/opencode2/api/session/ses_f86b8e080ffeABzd5eYNbYkAo3/context) ×2 · eventually(question settles and its session returns the actual answer) · desktopApi(GET /workspace/ws_3364c24dafcd/opencode2/api/session/ses_f86b8e080ffeABzd5eYNbYkAo3) · eventually(the native session records successful completion)
[user] see(text=/User has answered your questions:.
="Unrelated outline"/)
[probe] desktopApi(GET /workspace/ws_3364c24dafcd/opencode2/api/form/request) · desktopApi(GET /workspace/ws_3364c24dafcd/opencode2/api/session/ses_f86b8e770ffex8sBoi2dmHg118/context) · desktopApi(GET /workspace/ws_3364c24dafcd/opencode2/api/session/ses_f86b8ae9cffegPhsMiuaWKkq6m/context)
[user] screenshot
steps 1 ✅ an unrelated root waits for its own answer (4.3s) · 2 ✅ the parent displays only its delegated child's question (16.6s) · 3 ✅ reloading the parent restores the same unanswered requests (6.8s) · 4 ✅ answering in the parent resumes the original child and then the parent (8.0s) · 5 ✅ the unrelated root remains answerable without changing the parent's result (9.0s)
verdict passed · 14 user observations (see ×6, notSee ×6, screenshot ×2) · 41 probes · steps 5/5

⚪ UNVALIDATED — 1. a-parent-answers-its-real-child-question-without-settling-an-unrelated-root-ques artifact 1

  • UNVALIDATED — no visual expectations recorded.

⚪ UNVALIDATED — 2. a-parent-answers-its-real-child-question-without-settling-an-unrelated-root-ques artifact 2

  • UNVALIDATED — no visual expectations recorded.

Test run created 2026-09-07T00:21:08.846Z · Source: evals/results/test-runs/2026-09-07T00-21-08-846Z-a-parent-answers-its-real-child-question-without-settling-an-unrelated-root-ques/test-run.json · Repro: pnpm --dir evals artifacts:publish -- --pr 4590 --test-run 2026-09-07T00-21-08-846Z-a-parent-answers-its-real-child-question-without-settling-an-unrelated-root-ques

@diff-warden diff-warden 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.

Warden security clearance: clear. No blocking findings (security or desktop↔den sync) in this diff (d52e5dd87366a6bb1685fdafa5bd0360b840b6d1). Automated clearance satisfies the required-review gate only — a human still reviews and merges. Analysis run

@reachjalil
reachjalil merged commit 921e244 into dev Sep 8, 2026
28 checks passed
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