Skip to content

fix(memory): refresh shutdown session context - #7132

Open
dajiaohuang wants to merge 14 commits into
code-yeongyu:devfrom
dajiaohuang:fix/7114-shutdown-session-context
Open

fix(memory): refresh shutdown session context#7132
dajiaohuang wants to merge 14 commits into
code-yeongyu:devfrom
dajiaohuang:fix/7114-shutdown-session-context

Conversation

@dajiaohuang

@dajiaohuang dajiaohuang commented Aug 22, 2026

Copy link
Copy Markdown

Summary

  • Refresh memory's session-bound runtime context from the session_shutdown callback before running shutdown-triggered reflection.
  • Retire the old live ExtensionAPI before shutdown work starts, so a print-mode session replacement cannot make reflection reuse stale extension/session state.
  • Preserve the existing memory defaults and public interfaces while allowing shutdown outcomes to remain durable for the next session.

Changes

  • The memory component now passes the current shutdown callback context into the shutdown wiring.
  • The wiring updates its runtime resolver context and clears the retiring live session before draining reflection work.
  • A focused regression test covers both model resolution from the replacement context and the absence of the stale live session during the shutdown evaluator.
  • The checked-in Senpi plugin bundle was regenerated from the updated source.

QA & Evidence

  • What was tested: Focused shutdown wiring, drain, and trigger tests (three files).
    Observed result: 29 passed, 0 failed (70 assertions).
    Artifact: Local command output and .omo/evidence/omo-senpi-adapter/20260822-issue-7114-shutdown-context/.
    Why sufficient: Covers the shutdown wiring regression plus nearby reflection, runtime, and persistence behavior.
  • What was tested: tsgo --noEmit -p packages/omo-senpi/tsconfig.json and bun run build:senpi-plugin.
    Observed result: Both completed successfully; the generated plugin matches the source change.
    Artifact: Local command output and the committed plugin/extensions/omo.js diff.
    Why sufficient: Checks the affected package's types and distributable build path.
  • What was tested: Real Senpi 2026.8.22 print-mode session replacement with an isolated mock model.
    Observed result: The probe returned OK, no stale extension ctx error appeared, and the shutdown reflection reached a durable terminal outcome. The deliberately extension-free child could not see the parent-only mock model, so its recorded terminal state was failed/spawn_failed/model_not_visible rather than a completed reflection.
    Artifact: Sanitized local evidence in .omo/evidence/omo-senpi-adapter/20260822-issue-7114-shutdown-context/.
    Why sufficient: Exercises the reported lifecycle boundary using the real Senpi binary and proves shutdown no longer calls through the replaced session's stale context.

Risks & Residuals

  • Clearing the retiring live session means shutdown-triggered reflection uses the existing offline/durable completion path instead of appending through an API whose session is ending. This is limited to shutdown and is covered by the focused regression and real Senpi run.
  • bun run test:senpi was also attempted: 2,194 passed, 11 skipped, and 13 unrelated baseline/environment tests failed. The failures were Windows symlink-permission cases plus existing task-RPC and init-deep timer expectations; the new memory regression passed in that full run.
  • No default setting or public interface changes.

Automated Checks

bun test packages/omo-senpi/src/components/memory/wiring.test.ts packages/omo-senpi/src/components/memory/shutdown-drain.test.ts packages/omo-senpi/src/components/memory/dream-trigger-shutdown.test.ts
tsgo --noEmit -p packages/omo-senpi/tsconfig.json
bun run build:senpi-plugin
bun run test:senpi # 2194 passed, 11 skipped, 13 unrelated baseline/environment failures

Related Issues


Summary by cubic

Fixes memory shutdown so reflection resolves models from the current session_shutdown context instead of the stale bound session state, which could throw "stale extension context". Shutdown now retires the live session before reflection runs and tracks bind generations so a print-mode replacement session is not cleared by the retiring session's callback.

  • onSessionShutdown now receives and wires eventCtx; callers must pass the current eventCtx.
  • Adds a watch-based Senpi QA script proving print-mode session replacement and durable completion delivery into the next session, with recorded passing evidence, and regenerates the plugin bundle (including omo-task.js after the origin/dev merge).
  • Adds base-comparison evidence showing the remaining full-suite failures (Windows symlink EPERM and task-RPC cases) reproduce on the unmodified merge parent and origin/dev; the shutdown wiring test itself passes in that run.

Written for commit a11a830. Summary will update on new commits.

Review in cubic

@github-actions github-actions Bot added the omo-senpi Changes under packages/omo-senpi label Aug 22, 2026
@dajiaohuang
dajiaohuang force-pushed the fix/7114-shutdown-session-context branch from 413b5e5 to 5e1d26b Compare August 26, 2026 18:35
@dajiaohuang

Copy link
Copy Markdown
Author

Rebased this PR onto dev at 9c62b62 and regenerated the shipped Senpi bundle.\n\nValidation on the rebased head:\n- focused shutdown suites: 29 passed, 0 failed\n- official Senpi build and packages/omo-senpi typecheck: passed\n- real Senpi 2026.8.26 shutdown harness: passed (�xactAnswerObserved, staleExtensionContextAbsent, shutdownOriginRecorded, and
ealSenpiUntouched are all true)\n- fresh evidence: .omo/evidence/omo-senpi-adapter/20260827-pr-7132-rebase-shutdown-context/\n\nThe broader local Windows package run reached 2,264 passed / 14 skipped / 17 failed; the failures are outside this PR's touched wiring and are existing Windows/platform harness limits (for example symlink privileges and the POSIX mkdir -p QA helper). I did not expand this PR to alter those areas. Fresh CI is now running on the rebased head.

@MoerAI MoerAI left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The callback-context handoff is directionally correct, but the current evidence does not prove a successful shutdown reflection.

The live driver records spawn_failed / model_not_visible, so it proves only that one earlier failure string was absent:
https://github.com/code-yeongyu/oh-my-openagent/blob/5e1d26bcf683c08ecb1cafcdfe4d48d600c8e89d/.omo/evidence/omo-senpi-adapter/20260827-pr-7132-rebase-shutdown-context/result.json

Please make the isolated child model actually available and assert a successful shutdown reflection outcome and durable delivery. Replace the fixed 250 ms polling and empty JSON catch in the committed driver with a pre-subscribed completion signal and bounded timeout.

Also add a replacement-ordering regression. shutdown() clears the process-wide liveSession.current unconditionally, so prove that a retiring session callback cannot clear a newer bind for the same identity, or guard the clear by the bound session generation:

await rpcBridge.current?.sync()
},
shutdown(identity): void {
liveSession.current = undefined
if (identity !== undefined) activeRuns.clear(identity)
footerLive.dispose()
rpcBridge.current?.detach()
},
clearStatus(eventCtx): void {

Rebase onto current dev, regenerate the bundle, remove machine-local Windows paths and the obsolete evidence copy, then run the complete Senpi gate and current required matrix. Keep #7114 open until the successful lifecycle proof is green.

@AceRothstein71

Copy link
Copy Markdown

@dajiaohuang — heads up: this PR conflicts with current dev, and the conflicts are almost entirely in generated build artifacts, not your source.

Please don't hand-merge those files. The correct resolution is to take dev's copy and rebuild, because they are bundler output:

git fetch upstream dev && git rebase upstream/dev
# for any conflict under these paths, take dev's copy then rebuild:
#   packages/omo-senpi/plugin/extensions/
#   packages/omo-codex/scripts/install-dist/
#   packages/omo-codex/plugin/components/*/dist/
git checkout --ours <conflicted-artifact> && git add -f <conflicted-artifact>
git rebase --continue

bun install
node packages/omo-senpi/plugin/scripts/build-extension.mjs
bun run script/build-codex-install.ts
node packages/omo-codex/plugin/scripts/build-components.mjs   # must run from repo root
git add -f packages/omo-senpi/plugin/extensions packages/omo-codex/scripts/install-dist packages/omo-codex/plugin/components
git commit --amend --no-edit && git push -f

Two gotchas worth knowing: packages/omo-senpi/plugin/extensions is listed in .gitignore while still being tracked, so git add needs -f. And taking dev's bundle without rebuilding silently drops your fix from the shipped artifact — the rebuild step isn't optional.

I've already produced and verified this exact rebase locally for your branch (fix/7114-shutdown-session-context): it merges cleanly into dev with your authorship preserved and no changes dropped. I can't push it for you — I only have read access to the base repo, so I get a 403 against your fork despite maintainer_can_modify being enabled. If a maintainer wants to pull it in, or if you'd like the exact patch, say the word and I'll share it.

@AceRothstein71

Copy link
Copy Markdown

Correction to my previous comment — the recipe I posted was incomplete, sorry.

It omitted a staging step, and I found out the hard way: I applied that exact sequence to my own PRs, CI went red on three of them, and the failure was senpi-compatibility -> agent-toolkit runtime stale: staged ulw-loop sha256 ... does not match built sha256 ....

stage-agent-toolkit.mjs regenerates packages/omo-codex/plugin/components/ulw-loop/dist, and that file's sha is embedded in the Senpi bundle digest. It must run before build-extension.mjs, otherwise CI rejects the bundle via build-extension.mjs --check.

Corrected rebuild block:

bun install
node packages/omo-senpi/plugin/scripts/stage-agent-toolkit.mjs    # <-- was missing
node packages/omo-senpi/plugin/scripts/build-extension.mjs
bun run script/build-codex-install.ts
node packages/omo-codex/plugin/scripts/build-components.mjs
node packages/omo-senpi/plugin/scripts/build-extension.mjs --check  # verify before pushing
git add -f packages/omo-senpi/plugin/extensions packages/omo-codex/scripts/install-dist packages/omo-codex/plugin/components
git commit --amend --no-edit && git push -f

Run the --check line before pushing and CI will agree with you.

@dajiaohuang
dajiaohuang force-pushed the fix/7114-shutdown-session-context branch from 5e1d26b to bd533bb Compare September 2, 2026 06:55
@dajiaohuang

Copy link
Copy Markdown
Author

The review is correct about the evidence gap. I re-read the saved result: despite the top-level PASS, its shutdown completion is outcome: failed, reason: spawn_failed, with model_not_visible and deliveryStatus: pending. That proves neither successful reflection nor durable delivery. My earlier description of that harness run as passed was too broad; I withdraw that claim.

This PR remains blocked on a successful isolated-child shutdown/delivery proof, the replacement-session ordering regression, and regenerated artifacts with the complete current Senpi gate. The absence of the old context error is not sufficient, and #7114 should remain open.

dajiaohuang and others added 2 commits September 6, 2026 16:36
Take origin/dev generated Senpi bundle so the merge can complete; rebuild follows.

Co-authored-by: Cursor <cursoragent@cursor.com>
Guard liveSession teardown by bind generation so a print-mode
replacement is not cleared by the retiring session callback.
Regenerate the Senpi bundle and replace the withdrawn local evidence
with a watch-based driver that can see a child-visible mock model.

Co-authored-by: Cursor <cursoragent@cursor.com>
@dajiaohuang

Copy link
Copy Markdown
Author

Merged current origin/dev with a regular merge commit (no rebase / no force-push). Conflict was only packages/omo-senpi/plugin/extensions/omo.js; took dev''s copy, then rebuilt with stage-agent-toolkit.mjs before build-extension.mjs. --check is green (agent-toolkit sha256 da627576534832004728015abe6289c8bd7b313dbe31e6a4416fdfe2c4a3e561).

Code review items that are in this push (3d006be33):

  • shutdown() now records a bind generation and only clears liveSession / footer / RPC when the retiring generation is still current, so a later bind for the same identity is not wiped.
  • Replacement-ordering regressions cover a newer session id and a same-id print-mode rebind.
  • Focused suites: 36 passed / 0 failed (wiring.test.ts, shutdown-drain.test.ts, dream-trigger-shutdown.test.ts).
  • Removed the obsolete evidence copies that had machine-local Windows paths and the withdrawn PASS. The live driver now lives at packages/omo-senpi/scripts/qa/shutdown-context-e2e.mjs: child-visible models.json + 127.0.0.1 mock completions, fs.watch completion signal with a 25ms fallback (no 250ms poll, no empty JSON catch).

Remaining blocker — isolated-child success proof is still missing. I ran the new driver on this Windows host. Seed exited 0, the parent printed OK, and stale extension ctx was absent, but:

  • probeExitZero was false
  • no shutdown completion file appeared
  • wait for merged / no_changes timed out at 90s
  • wait for delivery.status=consumed timed out at 30s

That does not prove successful shutdown reflection or durable delivery. I am not claiming PASS. #7114 should stay open until a run records outcome: merged|no_changes and delivery.status: consumed.

dajiaohuang and others added 2 commits September 6, 2026 17:05
…ion-context

Co-authored-by: Cursor <cursoragent@cursor.com>

# Conflicts:
#	packages/omo-senpi/plugin/extensions/omo-task.js
Take dest's generated task bundle, then rebuild so the shipped artifact matches current source.

Co-authored-by: Cursor <cursoragent@cursor.com>
@dajiaohuang

Copy link
Copy Markdown
Author

@MoerAI I re-ran the isolated-child shutdown proof on the merged head. I am not claiming success.

What this run actually showed:

  • Driver: packages/omo-senpi/scripts/qa/shutdown-context-e2e.mjs (fs.watch + 90s/30s bounded waits, HTTP mock completions server, no 250ms poll, no empty-JSON catch).
  • Parent print-mode probe returned OK; stale extension ctx did not appear; real ~/.senpi/agent digest was unchanged.
  • The isolated child did spawn with --no-extensions --model omo-mock/mock-1. This is no longer spawn_failed / model_not_visible.
  • Child stdout was No memory changes required. and outcome.json recorded childExit.code: 0.
  • No reflection/completions/*.json with origin: shutdown was ever written. The harness therefore timed out: successful shutdown completion timed out after 90000ms and durable consumed delivery timed out after 30000ms.
  • Top-level checks: shutdownOriginRecorded=false, shutdownOutcomeSuccessful=false, durableDeliveryConsumed=false, probeExitZero=false. pending.json still pointed at a later reflection-run-2.

I am not attaching a PASS artifact. #7114 should stay open until a completion file is published and consumed (merged / no_changes + delivery.status=consumed).

Replacement-ordering is covered in unit tests on this head: a retiring shutdown() no longer clears a newer bind for the same identity/session id. Focused memory suites: 36 passed / 0 failed. build-extension.mjs --check and stage-agent-toolkit.mjs --check both passed with ulw-loop sha da627576534832004728015abe6289c8bd7b313dbe31e6a4416fdfe2c4a3e561.

@code-yeongyu

Copy link
Copy Markdown
Owner

CI failing on stale omo-senpi bundle. After omo-senpi source changes, rebuild and commit:

node packages/omo-senpi/plugin/scripts/build-extension.mjs
git add -f packages/omo-senpi/plugin/extensions/
git commit -m 'chore: rebuild senpi extension bundles'

@dajiaohuang

Copy link
Copy Markdown
Author

@MoerAI The isolated-child shutdown proof is now complete on commit 4e92160.

The real Senpi driver reports PASS with all eight checks true: the seed and replacement probes exit zero, the exact OK answer is observed, stale extension context is absent, a shutdown completion records origin: shutdown and outcome: no_changes, durable delivery reaches status: consumed, and the real ~/.senpi/agent is unchanged.

Evidence: .omo/evidence/omo-senpi-adapter/20260909-pr-7132-shutdown-context-recovery/README.md and result.json. The driver records a redacted sandboxAgentDir and sandboxCwd, validates the child environment through environment-receipt.ts, and tolerates only the expected ENOENT race while completed reflection worktrees are removed.

Focused shutdown and memory suites pass 36/36; the relevant QA contract checks pass 3/3 with the Git POSIX helper directory on PATH; stage-agent-toolkit.mjs --check and build-extension.mjs --check pass. The full local Windows package gate was attempted and reached 2674 pass, 41 skip, 11 fail; the residual failures are existing Windows symlink-privilege, POSIX mkdir helper, RPC, and unrelated status/workspace cases, summarized in the evidence README.

Fresh PR checks after the push are green. The PR remains open and dirty against the moving dev base; I have not merged or closed #7114.

@dajiaohuang

Copy link
Copy Markdown
Author

@MoerAI The successful isolated-child shutdown proof is now reproduced on the current dev base in merge commit db5a7bc2f28f23671af3cc9e0ea8b998dc0ea8a1.

What changed in this push:

  • merged origin/dev at adecbcf318ff33a9612996f5fa2994f9e8533707 with a regular merge commit;
  • preserved journal-first shutdown and passed input.sessionId into the generation-guarded reflectionLive.shutdown(...), so a retiring callback cannot clear a replacement bind;
  • focused wiring.test.ts: 21 passed, 0 failed;
  • tsgo --noEmit -p packages/omo-senpi/tsconfig.json: passed;
  • stage-agent-toolkit.mjs --check and build-extension.mjs --check: passed.

The real Senpi driver now reports PASS with all eight checks true: seed/probe/delivery exit successfully, the exact OK answer is observed, stale extension context is absent, the completion records origin: shutdown and outcome: no_changes, delivery reaches consumed, and realSenpiUntouched is true. The structured result and reviewer-readable evidence are at .omo/evidence/omo-senpi-adapter/20260909-pr-7132-shutdown-context-recovery/driver-result.json and README.md.

I also ran the complete local bun run test:senpi gate after the fix. Its actual result was 2,988 passed, 41 skipped, 9 failed, plus 1 unhandled timeout across 3,038 tests. The residual failures are the Windows symlink-permission cases, the existing Windows process-mode RPC gap, the task-status spend case, and the released-child supervisor timeout; the shutdown-context wiring test passed. I am reporting this as a residual local gate limitation rather than claiming a green full gate.

GitHub currently reports the PR as MERGEABLE; required checks are still pending. I have not merged or closed the PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

omo-senpi Changes under packages/omo-senpi

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants