Skip to content

fix(activity): stabilize codex and opencode states#6

Draft
integrate-your-mind wants to merge 42 commits into
mainfrom
fix/activity-state
Draft

fix(activity): stabilize codex and opencode states#6
integrate-your-mind wants to merge 42 commits into
mainfrom
fix/activity-state

Conversation

@integrate-your-mind

@integrate-your-mind integrate-your-mind commented Jan 30, 2026

Copy link
Copy Markdown
Owner

Summary

  • stabilize codex in-flight end handling with tool-aware grace and per-process JSONL selection
  • make OpenCode completion authoritative and prevent stale false positives while keeping TUI activity consistent
  • resolve wheel passive listener warning and align config/docs/tests with new activity defaults

Testing

  • npm test

Open with Devin

Ensure codex in-flight ends within 2.5s of completion, pick active JSONL per process, and make opencode message completion authoritative. Remove wheel passive listener warnings and align docs/tests.
Start the server on the next available port during dev and ignore stale OpenCode status events when determining in-flight state.
@integrate-your-mind

Copy link
Copy Markdown
Owner Author

@codex

1 similar comment
@integrate-your-mind

Copy link
Copy Markdown
Owner Author

@codex

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

ℹ️ 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 src/opencodeEvents.ts Outdated

@devin-ai-integration devin-ai-integration 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.

Devin Review found 1 potential issue.

View issue and 9 additional flags in Devin Review.

Open in Devin Review

Comment thread src/codexLogs.ts

@devin-ai-integration devin-ai-integration 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.

Devin Review found 1 new potential issue.

View issue and 9 additional flags in Devin Review.

Open in Devin Review

Comment thread src/scan.ts

@devin-ai-integration devin-ai-integration 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.

Devin Review found 1 new potential issue.

View issue and 9 additional flags in Devin Review.

Open in Devin Review

Comment thread public/src/lib/layout.ts

@devin-ai-integration devin-ai-integration 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.

Devin Review found 1 new potential issue.

View issue and 28 additional flags in Devin Review.

Open in Devin Review

Comment thread src/codexLogs.ts
@integrate-your-mind integrate-your-mind self-assigned this Feb 3, 2026

@devin-ai-integration devin-ai-integration 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.

Devin Review found 1 new potential issue.

View issue and 27 additional flags in Devin Review.

Open in Devin Review

Comment thread src/opencodeApi.ts

@devin-ai-integration devin-ai-integration 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.

Devin Review found 2 new potential issues.

View 30 additional findings in Devin Review.

Open in Devin Review

Comment thread src/codexLogs.ts
Comment thread src/codexLogs.ts
- Tail Codex JSONL incrementally when log growth exceeds MAX_READ_BYTES and surface catch-up via TailState.needsCatchUp.

- Apply shouldParseJsonLine() before JSON.parse to skip noisy delta lines while still recording ingest time.

- Add integration coverage for needsCatchUp behavior.

@devin-ai-integration devin-ai-integration 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.

Devin Review found 2 new potential issues.

View 28 additional findings in Devin Review.

Open in Devin Review

Comment thread public/src/lib/layout.ts Outdated
Comment thread src/cli/setup.ts
@integrate-your-mind

Copy link
Copy Markdown
Owner Author

Review comment fixes pushed (4 commits):\n\n- fix(codex): ignore token_count for pending-end markers (65b2b43)\n- fix(setup): merge required codex notifications (c98983c)\n- fix(ui): avoid spatial cell-key wrapping (2d1c9bd)\n- test(ui): filter live TUI demo lane by match query (c5d17d9)\n\nBuild gate:\n- npm run build: ✓ built in 360ms\n\nTest gate:\n- npm run test:unit: # pass 171 # fail 0\n- npm run test:integration: # pass 71 # fail 0\n\nUI gate:\n- npm run test:ui: 19 passed (6.2s), 2 skipped (env-gated demos)\n\nEvidence gate (flicker):\n- tmp/flicker-summary.json (intervalMs=250 durationMs=120000 windowMs=10000 totalFlickerCount=0)\n- tmp/flicker-summary.transitions.jsonl\n\nDemo video gate (live TUI):\n- Playwright raw: test-results/ui-codexTuiLiveDemo.pw.ts--c9c35--active---idle-30s-capture-/video.webm\n- Trimmed 30s mp4: tmp/codexTuiLiveDemo-30s.mp4

@integrate-your-mind

Copy link
Copy Markdown
Owner Author

CI fix: npm test now works in bash (GitHub Actions) without relying on ** globstar.\n\n- Commit: cf91d42 fix(test): make npm test portable across shells\n- Added scripts/run-node-tests.js and updated package.json test scripts.\n\nLocal verification (summary lines):\n- npm run build: ✓ built in 331ms\n- npm test: unit # pass 171 # fail 0; integration # pass 71 # fail 0\n\nGitHub Actions:\n- build check now passing (run 21740671370).

@devin-ai-integration devin-ai-integration 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.

Devin Review found 1 new potential issue.

View 40 additional findings in Devin Review.

Open in Devin Review

Comment thread src/codexLogs.ts Outdated
@integrate-your-mind

Copy link
Copy Markdown
Owner Author

Follow-up fix for latest Devin inline review comment (src/codexLogs.ts stale-file cleanup):

  • Commit: 9232125 fix(codex): clear stale tail markers
  • Change: when a session JSONL file is stale, updateTailLegacy now clears all in-flight markers (pendingEndAt, turnOpen, reviewMode, openCallIds, openItemCount, etc) regardless of state.inFlight, preventing ghost summary.inFlight.
  • Added unit regression: tests/unit/staleFileCleanup.test.ts
  • Postmortem updated: docs/postmortem-codex-activity-flicker.md

Build gate:

  • npm run build: ✓ built in 308ms

Test gate:

  • npm run test:unit: # pass 172 # fail 0
  • npm run test:integration: # pass 71 # fail 0 (skipped 3)

@devin-ai-integration devin-ai-integration 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.

Devin Review found 1 new potential issue.

View 46 additional findings in Devin Review.

Open in Devin Review

Comment thread src/codexLogs.ts
Comment on lines 852 to 857
const expireInFlight = () => {
if (!state.inFlight) return;
if (!Number.isFinite(inflightTimeoutMs) || inflightTimeoutMs <= 0) return;
if (process.env.CODEX_TEST_HOOKS === "1") {
"TEST_HOOK_EXPIRE_CHECK";
}
if (!state.inFlight && !state.pendingEndAt) return;
if (!Number.isFinite(inflightTimeoutMs) || inflightTimeoutMs <= 0) return;

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 tail expiration can get stuck when turnOpen/openCallIds are set but state.inFlight is false

Codex tail state can become permanently inFlight (via summarizeTail) because expireInFlight() returns early unless state.inFlight or pendingEndAt is set.

Root Cause & Impact

expireInFlight() starts with:

  • if (!state.inFlight && !state.pendingEndAt) return; (/home/ubuntu/repos/repo-ab792c74ddf9424a89ed9851e3e65943/src/codexLogs.ts:852-857)

But summarizeTail() treats a session as in-flight if any of these are true: turnOpen, openCallCount > 0, reviewMode, or pendingEndAt (/home/ubuntu/repos/repo-ab792c74ddf9424a89ed9851e3e65943/src/codexLogs.ts:1506-1511).

There are code paths that set turnOpen and/or openCallIds/openItemCount even when canSignal is false (so state.inFlight may remain false):

  • Turn/thread start sets state.turnOpen = true unconditionally, and only sets state.inFlight = true inside the if (canSignal) block (/home/ubuntu/repos/repo-ab792c74ddf9424a89ed9851e3e65943/src/codexLogs.ts:1115-1123).
  • Tool-call start adds to openCallIds / increments openItemCount unconditionally, and only sets state.inFlight = true inside the if (canSignal) block (/home/ubuntu/repos/repo-ab792c74ddf9424a89ed9851e3e65943/src/codexLogs.ts:1237-1256).

If canSignal is false (e.g., timestamp considered stale by CONSENSUS_CODEX_SIGNAL_MAX_AGE_MS, or file is stale and keepStale is false), the state can end up with turnOpen=true or openCallCount>0 while state.inFlight=false and pendingEndAt unset. In that case:

  • summarizeTail() reports inFlight=true (because turnOpen/openCallCount contributes).
  • expireInFlight() never runs and never clears turnOpen/open-call tracking.

Actual: agent can stay incorrectly active indefinitely.

Expected: stale/unsignalable events should not create sticky turnOpen/open-call state, or expiration should still run when these markers are set.

Prompt for agents
In src/codexLogs.ts, make expireInFlight() consider all fields that contribute to summarizeTail().inFlight, not just state.inFlight/pendingEndAt.

Concretely:
1) In updateTailLegacy(), change the early return in expireInFlight() (currently: if (!state.inFlight && !state.pendingEndAt) return;) so it also runs when state.turnOpen is true, state.reviewMode is true, or openCallCount > 0.

2) Alternatively (or additionally), prevent turnOpen/open-call tracking from being set when canSignal is false (stale/unsignalable events). For example:
- In the isTurnStart/isResponseStart branches and tool-call start branches, gate state.turnOpen mutation and openCallIds/openItemCount mutations behind canSignal.

3) Add/adjust a unit/integration test demonstrating the stuck-active case: write a stale-timestamp turn.started or tool-call event that sets turnOpen/openCallCount while canSignal=false, then verify a later updateTail call can clear/expire the in-flight summary.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown
Owner Author

Backlog triage status

This remains the canonical activity-stability branch and should merge before #26 and before rebasing #29, but it is not merge-ready yet.

Cleared during triage

  • Resolved the outdated OpenCode paused/stopped-status thread; the current code already normalizes those states as idle.
  • Resolved the outdated stale-file cleanup thread; the current stale-file branch clears inFlight, turnOpen, reviewMode, pending-end state, and open calls regardless of the prior state.inFlight value.

Live blocker

expireInFlight() still returns immediately when both state.inFlight and pendingEndAt are unset. That return occurs before it checks turnOpen, reviewMode, or open calls, although those fields also make summarizeTail() report the session as in flight. Start/tool events can set those structural markers when canSignal is false, leaving a ghost-active session with no expiry path.

Required fix:

  1. Do not create turnOpen, review, or open-call markers from stale/unsignalable start events.
  2. Make expiry clean up an inconsistent state where state.inFlight === false but structural in-flight markers remain.
  3. Add a regression using a stale turn/tool start and a later no-growth tail update; the final summary must become idle.

The current head has no attached combined status checks, and there is no approving review. Returning this PR to draft until the blocker is fixed and the focused test passes.

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.

1 participant