Skip to content

fix: separate session containment from opened-by provenance - #569

Merged
wibus-wee merged 6 commits into
mainfrom
fix/session-containment-lifecycle
Sep 10, 2026
Merged

wibus-wee merged 6 commits into
mainfrom
fix/session-containment-lifecycle

Conversation

@wibus-wee

@wibus-wee wibus-wee commented Sep 10, 2026

Copy link
Copy Markdown
Member

Related issue

Closes #531

Problem / pressure

Desktop and mobile treated openedBySessionId and openedByRootSessionId as lifecycle ownership edges. Archive/restore could stop an independently owned Session, and the natural archive-then-delete flow could permanently delete that still-active Session and its worktree without warning.

A later safety gate also made deleteSessions(ids) wait for complete metadata, even though its production callers use it for exact compensation and cleanup during hydration.

Summary

  • Make archive, restore, and archived-root permanent delete affect only the selected Session plus direct parentSessionId child Tabs.
  • Keep deleteSessions(ids) exact: delete only the supplied ids, with no relation discovery or metadata-readiness requirement.
  • Preserve independently opened Sessions, their worktrees, launch configs, machine commands, and legacy queue entries.
  • Keep openedBy* metadata as provenance after an opener is deleted. Once metadata hydration proves that the exact opener or route root is missing, show deleted-session provenance without a working navigation action.
  • Require complete metadata only for deleteArchivedSession(rootId), where the operation must discover the destructive set.
  • Add draft specs/session-relations.md as the durable relation and operation-target contract.
  • Remove the recursive collectSessionLifecycleIds graph and its opened-descendant contract. Keep archived opened-by tree construction as presentation behavior.

No tombstone store, relationship policy layer, recursive nested-child behavior, or supervised-worker product from #529 is introduced.

Visual explanation

flowchart LR
  A[Session A] -->|parentSessionId| T[Tab T]
  A -. openedBySessionId .-> B[Session B]
  T -. openedBySessionId .-> C[Session C]
  A == archive / restore / archived-root delete ==> T
  A -. keep independent .-> B
  T -. keep independent .-> C
Loading

The solid edge is containment and selects root-operation targets. The dotted edges are provenance only. Exact cleanup does not traverse either edge: deleteSessions([X]) deletes only X.

Before / after

Before After
Archive/restore A could cascade to A, T, B, and C. Archive/restore affects only A and T.
Archive A kept B active, but permanent delete A rediscovered B through the legacy lifecycle graph and deleted it. Archived-root delete selects only A and direct child T; B/C documents and resources survive.
Exact cleanup waited for full metadata and could fail after a partial child create, empty Tab close, or side-runtime termination. deleteSessions(ids) removes exactly the known ids during hydration and never discovers extra targets.
An id alone created a reverse-navigation target, even after the opener disappeared. Navigation requires complete metadata plus the precise opener and route root; dangling provenance is visible but disabled.
Durable guarantees existed only in implementation notes and local rules. A draft Spec owns relation meaning, operation targets, destructive side effects, dangling provenance, and the #574 implementation gap.
A recursive Map/Set/BFS mixed containment and provenance, including unsupported nested children. Operation-local direct-child selection matches supported product paths and CLI/MCP.

Test plan

  • use-session-actions.test.ts: 33/33 passed, including incomplete-cache exact Tab deletion, partial-create compensation, archive/restore isolation, archive-then-delete, and incomplete-cache archived-root rejection.
  • SessionManager.requestSessionTerminate: 4/4 passed. A retry after the runtime is gone returns not-found; the RPC handler maps that result to success, so side-session termination retry is idempotent at the RPC boundary.
  • Navigation, relation-card, and archived-tree suites passed 15/15. The dangling-provenance header-menu case also passed; an unrelated existing reviewer-menu fixture failed locally.
  • Components typecheck, type-aware lint, docs check, i18n, collaboration-import, platform-boundary, and public-boundary checks passed.
  • The root pnpm check wrapper could not start in this shell because its hardcoded corepack executable is unavailable. The directly invokable affected checks above passed; GitHub CI is authoritative for the full matrix.

Follow-up

#574 continues to track the pre-existing archive cold-start race where Session Detail may expose Archive before all direct child Tabs hydrate. The draft Spec records the intended complete-target contract and the current implementation gap.

Context handoff

Instructions for reviewing agents

  • Review focus: Verify archive/restore and archived-root delete select only the root plus direct parentSessionId Tabs. Verify deleteSessions(ids) deletes only supplied ids and remains usable before metadata hydration. Review the draft Spec as the owner of these guarantees.
  • Decisions to challenge: Confirm dangling openedBy* remains historical provenance while navigation requires both the exact opener and route root after hydration.
  • Plausible failures / evidence gaps: Archive and restore still select from sessionMetaCacheAtom; [Bug] Archive can miss child Tabs before metadata cache hydration #574 tracks their pre-hydration completeness race.

Authoring context

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 10, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-10T11:47:20.200045Z 50d8a62 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@wibus-wee wibus-wee changed the title fix: preserve opened session lifecycle ownership fix: preserve opened sessions during archive cascades Sep 10, 2026

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3620c06691

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +47 to +50
- Root archive, restore, and permanent delete include only direct child Tabs whose
`parentSessionId` equals the root id. Independently opened Sessions keep their own
state and resources. Permanent deletion requires a complete metadata cache before
selecting targets; nested child Sessions are unsupported. Keep dangling `openedBy*`

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Add a draft Spec for the lifecycle guarantee

This introduces binding archive, restore, permanent-delete, and dangling-navigation semantics, but records them only in an AGENTS rule, implementation documentation, and an Agent Note. Add or update the owning public session-lifecycle Spec with Status: draft; otherwise these destructive ownership semantics ship without the repository's required human-reviewable intent contract.

AGENTS.md reference: AGENTS.md:L15-L17

Useful? React with 👍 / 👎.

@wibus-wee wibus-wee changed the title fix: preserve opened sessions during archive cascades fix: separate session containment from opened-by provenance Sep 10, 2026
@wibus-wee
wibus-wee merged commit 1561f71 into main Sep 10, 2026
7 checks passed
@wibus-wee
wibus-wee deleted the fix/session-containment-lifecycle branch September 10, 2026 13:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] Desktop archive of an opener also archives independent openedBy sessions

1 participant