Skip to content

feat(preview): identify and stop retained thread processes - #280

Merged
lastobelus merged 13 commits into
lastcode/mainfrom
lastcode/preview-process-controls
Oct 5, 2026
Merged

lastobelus merged 13 commits into
lastcode/mainfrom
lastcode/preview-process-controls

Conversation

@lastobelus

@lastobelus lastobelus commented Oct 5, 2026 •

Copy link
Copy Markdown
Owner

Retained previews look like unexplained terminal processes after a thread finishes, and there is no single way to stop them. Show process identities and preview expiry in the sidebar hover, and offer “Stop all previews & processes” only when the thread has something to stop.

Group the thread menu with dividers and add shutdown feedback across web, desktop, and mobile. Feedback appears immediately and stays through terminal cleanup or three seconds, whichever takes longer; stopping a preview also cancels its retained recovery lease. Cleanup waits for an actual PTY exit event and holds the thread lock so concurrent opens or restarts cannot escape the stop. Unconfirmed termination stays visible and retryable; a later exit clears its indicator. Terminal attachment cannot start a replacement while the previous process is still terminating. Mobile tracks concurrent stops independently; interruption removes only its own feedback, and completed outcomes remain visible alongside pending shutdowns.

Validation runs in GitHub CI only at the maintainer's request. Regression coverage includes shutdown and retry, actual exit confirmation, delayed and cached exits, thread locking and isolation, late metadata removal, observer cleanup, attachment during termination, tool presentation, and concurrent mobile feedback timing and interruption. Integrated Browser checks covered preview expiry, conditional menus, thread isolation, fast three-second feedback, and delayed shutdown feedback. Desktop QA was accepted by the user. Native mobile visual QA was not run. The complete change receives independent Astra High source review and exact-head Codex review.

Before/after screenshots and shutdown timing recordings: #280 (comment).

Implemented with GPT-6.1-Sol in the Codex harness.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 5, 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-10-05T23:37:05.820348Z 21761e8 Manual request
ℹ️ 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.

@lastobelus

Copy link
Copy Markdown
Owner Author

@codex review

@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: d808a37024

ℹ️ 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 thread apps/server/src/preview/Hosting.ts Outdated
@lastobelus

lastobelus commented Oct 5, 2026 •

Copy link
Copy Markdown
Owner Author

Earlier accepted Browser QA, captured before rebasing this branch onto the current base. These show the conditional stop command/menu grouping and feedback during delayed shutdown. Fresh base/head screenshots and a timing recording are still being prepared.

Stop command and menu grouping

Feedback while shutdown remains pending

@lastobelus

Copy link
Copy Markdown
Owner Author

UI evidence for c5afeb68adbf8792b76699b98fb21c457a513ad1, compared with the actual ea46593bbb08c1bde63ee9d249674012341b61af baseline frontend. Both use isolated QA data.

The baseline and updated menu screenshots show the conditional stop command and new dividers. The confirmation and pending screenshots show shutdown feedback. The fast recording captures a normal stop. The slow recording delays only the selected thread’s stop request by four seconds: loading feedback remains for 5.1 seconds until completion, then confirms shutdown. The selected thread’s process indicator disappears; the unrelated thread still has its running process.

Astra High round 2 reviewed the whole PR at this head/base and found no actionable defects. Native mobile presentation was not tested on a device.

before-menu

after-menu

confirmation

pending-shutdown

fast-stop.mp4
slow-stop.mp4

@lastobelus

Copy link
Copy Markdown
Owner Author

@codex review

@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: c5afeb68ad

ℹ️ 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 thread apps/mobile/src/features/threads/thread-list-v2-items.tsx
@lastobelus
lastobelus force-pushed the lastcode/preview-process-controls branch from c5afeb6 to 123e6cb Compare October 5, 2026 22:00
@lastobelus

Copy link
Copy Markdown
Owner Author

@codex review

@lastobelus
lastobelus force-pushed the lastcode/preview-process-controls branch from 123e6cb to 41eeae1 Compare October 5, 2026 22:03
@lastobelus

Copy link
Copy Markdown
Owner Author

@codex review

@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: 41eeae1deb

ℹ️ 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 thread apps/server/src/terminal/Manager.ts Outdated
@lastobelus

Copy link
Copy Markdown
Owner Author

@codex review

@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: fb5b7d0b8b

ℹ️ 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 thread apps/server/src/terminal/Manager.ts
Comment thread apps/mobile/src/state/stop-thread-processes-feedback.ts Outdated
@lastobelus
lastobelus force-pushed the lastcode/preview-process-controls branch from fb5b7d0 to f0188c0 Compare October 5, 2026 22:56
@lastobelus

Copy link
Copy Markdown
Owner Author

@codex review

Show each managed preview expiry next to its terminal process. Offer a thread-only stop command when a preview or subprocess remains, with grouped menus across clients and cancellation that interrupts recovery.

Carry-Group: incubator
Carry-Observation: Preview lifecycle metadata and cancellation share one service and typed client contract, so the core change must travel together.
Offer the shared thread preview and process stop command in the legacy sidebar, with dividers after new-thread, annotation, and persistence controls.

Carry-Group: legacy-sidebar
Carry-Observation: Optional legacy sidebar integration reuses the core preview control service.
Carry-Group: incubator

Preview lease subscriptions now wait for the selected session and recheck its capability after reconnecting. Focused tests cover startup, reconnect, unsupported servers, and session-tagged fallback values.

Implemented with GPT-6.1-Sol in the Codex harness.
Carry-Group: incubator

Show immediate shutdown feedback in web, desktop, and native mobile, retaining it through completion and for at least three seconds. The stop service now awaits the selected thread’s existing terminal cleanup fibers and reports failed termination.

Validation: focused backend and mobile timing tests, scoped typechecks and lint, and Browser checks for three-second and delayed shutdown feedback.

Implemented with GPT-6.1-Sol in the Codex harness.
Keep failed terminal handles visible and retry their termination on a later stop. Hold the thread lock while selecting, closing, and awaiting cleanup so concurrent opens and restarts cannot escape that shutdown interval.

Validation: 135 focused backend tests, scoped server typecheck, lint, and formatting passed.

Implemented with GPT-6.1-Sol in the Codex harness.

Carry-Group: incubator
Register lifecycle labels, branding, and a summary action for preview_stop_thread so every published MCP tool has a presentation definition.

Validation: 14 registry and tool presentation tests, shared typecheck, scoped lint and formatting passed.

Implemented with GPT-6.1-Sol in the Codex harness.

Carry-Group: incubator
Dismiss the global shutdown feedback when the environment interrupts the stop request, instead of showing a failure that cannot be confirmed. Retire interrupted feedback so a late completion cannot revive it, and preserve feedback from a newer request.

Validation: six focused feedback tests, mobile typecheck, scoped lint, formatting, and diff checks passed.

Implemented with GPT-6.1-Sol in the Codex harness.

Carry-Group: incubator
Wait for actual PTY exit callbacks before reporting that retained processes stopped. Bound confirmation after force-kill, keep unconfirmed processes visible and retryable, and remove their metadata if an exit arrives later.

Add regression cases for cached and delayed exit, timeout and retry, thread locking and isolation, and exit subscription cleanup. Clarify the PTY adapter's termination contract and make test PTYs emit actual exit events.

Formatting and diff checks passed. Tests and typechecks run in GitHub CI only at the maintainer's request.

Implemented with GPT-6.1-Sol in the Codex harness.

Carry-Group: incubator
Track each shutdown independently so finishing or interrupting one request cannot clear another pending stop. Show aggregate progress and completed outcomes, retaining each result for its own minimum visibility.

Add deterministic concurrency regression cases. Source formatting and diff checks completed; validation runs in GitHub CI only at the maintainer request.

Implemented with GPT-6.1-Sol in the Codex harness.

Carry-Group: incubator
Reject automatic attachment while the same terminal still has an unconfirmed retained exit witness and no live session process. Keep retained processes visible and retryable, and allow normal attachment after confirmed exit or to an intentional live replacement.

Add deterministic regressions for termination grace, repeated attachment after failed shutdown, processless replacements and thread isolation. Source formatting and diff checks completed; tests run in GitHub CI only at the maintainer request.

Implemented with GPT-6.1-Sol in the Codex harness.

Carry-Group: incubator
Capture attachment lifecycle before waiting for the thread lock. Keep a temporary count of shutdown operations through lock finalization so metadata removal or an interrupted concurrent stop cannot let an automatic attachment recreate a terminal.

Add deterministic coverage for queued attachment, delayed metadata removal, concurrent idle close and interrupted shutdown. Fresh attachment remains possible after shutdown completes. Source formatting and diff checks passed; test execution is delegated to GitHub CI at the maintainer request.

Implemented with GPT-6.1-Sol in the Codex harness.

Carry-Group: incubator
Hold the closed-event consumer awaited by shutdown itself instead of an independently published metadata-removal event. This proves the attachment is queued while Stop owns the lock after metadata disappears, regardless of exit-observer scheduling.

Source formatting and diff checks completed. Test execution runs in GitHub CI only at the maintainer request.

Implemented with GPT-6.1-Sol in the Codex harness.

Carry-Group: incubator
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 🚀

Reviewed commit: f0188c0626

ℹ️ 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".

@lastobelus
lastobelus force-pushed the lastcode/preview-process-controls branch from f0188c0 to b7b28ff Compare October 5, 2026 23:05
@lastobelus

Copy link
Copy Markdown
Owner Author

@codex review

@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: b7b28ff801

ℹ️ 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 thread apps/server/src/preview/Hosting.ts Outdated
Stopping a slow process held the environment-wide preview reservation gate until its terminal exited, delaying unrelated launches. Order reservations and cleanup by thread, while retaining the short shared gate for atomic port ownership and keeping readiness cancellable.

Added deterministic regressions for blocked shutdown, same-thread ordering, concurrent port reservations, and immediate launch/recovery cancellation. Source formatting and diff checks passed; tests run in GitHub CI only at the maintainer request.

Implemented with GPT-6.1-Sol in the Codex harness.

Carry-Group: incubator
@lastobelus

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Hooray!

Reviewed commit: 21761e8d35

ℹ️ 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".

@lastobelus
lastobelus merged commit f6e953e into lastcode/main Oct 5, 2026
17 checks passed
@lastobelus
lastobelus deleted the lastcode/preview-process-controls branch October 5, 2026 23:39
lastobelus added a commit that referenced this pull request Oct 7, 2026
A merge that landed while a checkpoint was validating discarded the run: repaired checkpoints published tag and main in one atomic push, so the validated tag was rejected and the repair had to be reselected and revalidated by hand; ordinary checkpoints published their tag but failed the run at promotion. Publish the validated tag and source ref without touching main, and have promotion defer, instead of failing, when main advanced or a guarded merge holds the main write lock. The merge's own service request then publishes a revision that replays it onto the new tag and promotes that. Merges after recovery selection no longer invalidate it; only a main that no longer descends from the selected source does.

Carry-Group: tooling
Carry-Observation: On 2026-10-05 the merges of #280 and #282 each forced a manual fold-in and full revalidation of a repaired checkpoint.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
lastobelus added a commit that referenced this pull request Oct 7, 2026
A merge that landed while a checkpoint was validating discarded the run: repaired checkpoints published tag and main in one atomic push, so the validated tag was rejected and the repair had to be reselected and revalidated by hand; ordinary checkpoints published their tag but failed the run at promotion. Publish the validated tag and source ref without touching main, and have promotion defer, instead of failing, when main advanced or a guarded merge holds the main write lock. The merge's own service request then publishes a revision that replays it onto the new tag and promotes that. Merges after recovery selection no longer invalidate it; only a main that no longer descends from the selected source does.

Carry-Group: tooling
Carry-Observation: On 2026-10-05 the merges of #280 and #282 each forced a manual fold-in and full revalidation of a repaired checkpoint.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
lastobelus added a commit that referenced this pull request Oct 7, 2026
A merge that landed while a checkpoint was validating discarded the run: repaired checkpoints published tag and main in one atomic push, so the validated tag was rejected and the repair had to be reselected and revalidated by hand; ordinary checkpoints published their tag but failed the run at promotion. Publish the validated tag and source ref without touching main, and have promotion defer, instead of failing, when main advanced or a guarded merge holds the main write lock. The merge's own service request then publishes a revision that replays it onto the new tag and promotes that. Merges after recovery selection no longer invalidate it; only a main that no longer descends from the selected source does.

Carry-Group: tooling
Carry-Observation: On 2026-10-05 the merges of #280 and #282 each forced a manual fold-in and full revalidation of a repaired checkpoint.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
lastobelus added a commit that referenced this pull request Oct 7, 2026
A merge that landed while a checkpoint was validating discarded the run: repaired checkpoints published tag and main in one atomic push, so the validated tag was rejected and the repair had to be reselected and revalidated by hand; ordinary checkpoints published their tag but failed the run at promotion. Publish the validated tag and source ref without touching main, and have promotion defer, instead of failing, when main advanced or a guarded merge holds the main write lock. The merge's own service request then publishes a revision that replays it onto the new tag and promotes that. Merges after recovery selection no longer invalidate it; only a main that no longer descends from the selected source does.

Carry-Group: tooling
Carry-Observation: On 2026-10-05 the merges of #280 and #282 each forced a manual fold-in and full revalidation of a repaired checkpoint.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
lastobelus added a commit that referenced this pull request Oct 7, 2026
Merging a PR while a checkpoint was validating threw the run away. Repaired checkpoints published the tag and `lastcode/main` in one `--atomic` push, so a mid-run merge rejected the validated tag too. The repair then had to be reselected, with the merge folded in by hand, and fully revalidated. Ordinary checkpoints published their tag but failed the run at promotion, which alerted the maintenance thread. On 2026-10-05, #280 and #282 each cost a manual fold-in and a 10–15 minute revalidation.

The validated tag no longer depends on main:

- **Repaired checkpoints** publish the tag and immutable source ref atomically, then promote separately, the same as ordinary checkpoints.
- **Promotion defers instead of failing** when main has advanced to a descendant of the candidate's source or git's lease rejects the push because a descendant merge landed mid-push. A rewrite that drops the pinned source still fails promotion after tag publication, and the rejected-push path fetches the competing head before checking ancestry. The run succeeds and logs that promotion is left to the next run. Failure to acquire the promotion lock still fails the run after the tag publishes; the lock ref cannot prove its writer is active, and abandoned locks or authentication/transport errors must remain visible to maintenance.
- The guarded merge already requests a service run, and the supervisor runs it straight after the current run. That run publishes a revision replaying only the merged work onto the new tag, then promotes it. If main still equals the source, it promotes the published tag directly.
- **Merges after recovery selection no longer invalidate it.** Only a main that no longer descends from the selected source (for example, rewritten by another promotion) requires reselection.
- **Recovery cleanup follows promotion validation.** A main rewrite or promotion failure keeps the repaired worktree and selection for inspection. Retry promotes the existing immutable tag without republishing; successful promotion or validated descendant deferral releases the repair.

You can merge at any time. The build can start from the checkpoint tag immediately, and merged work follows minutes later as a revision.

Runbook text in `fork-conventions.md`, `release.md`, `nightly-workflow.md` and the `lastcode-pr` skill is rewritten to match.

Validation: focused checkpoint and recovery tests, selected-recovery lifecycle tests, and carry lifecycle tests pass. Lifecycle regressions cover descendant merges after selection, during validation, and during the promotion push; unrelated remote-only rewrites retain the selected repair and fail visibly while preserving the published tag and rewritten main. They also verify blocked retries preserve that repair, restored-source retries promote the existing tag, and promotion-lock failures retain recovery until a successful retry. The scripts typecheck and scoped format/lint checks pass. GitHub CI and Codex review are required on the final head and base. Quick CI was skipped at the maintainer's request; GitHub CI is the gate.

Includes merged #293 as its current base.

Implemented with Claude Opus 5.5 in the Claude Code harness. Refreshed and repaired with GPT-6.1-Sol in the Codex harness.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Carry-Source-Ref: refs/lastcode/carry-sources/pr-294/e70ba03bd32f5e16161d968d3da613b6bd5b0d9b
Carry-Source-Base: 00eaf51
Carry-Source-Head: e70ba03
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