Skip to content

fix(session): clear stale pending interactions - #748

Merged
Astro-Han merged 5 commits into
devfrom
pawwork/i744-session-pending-cleanup
May 19, 2026
Merged

fix(session): clear stale pending interactions#748
Astro-Han merged 5 commits into
devfrom
pawwork/i744-session-pending-cleanup

Conversation

@Astro-Han

@Astro-Han Astro-Han commented May 19, 2026

Copy link
Copy Markdown
Owner

Summary

  • Add session-scoped cleanup for pending question, permission, and blocker state when sessions are deleted or archived.
  • Defensively prune missing-session pending interactions from question, permission, and blocker list routes, terminating the stale deferred work instead of returning it to the UI.
  • Treat frontend warm-session 404s as a race fallback by filtering those pending entries from bootstrap stores, and stop logging expected NotFoundError responses as server ERROR failed entries.

Why

Installed builds could surface stale in-memory pending interaction state for a session that no longer exists, causing repeated session warm-up 404s and uncaught promise errors during bootstrap. The backend now owns the lifecycle invariant, while the app bootstrap keeps a narrow race fallback.

Related Issue

Closes #744

Human Review Status

Pending. A human should make the final merge decision after reviewing the final diff and verification evidence.

Review Focus

  • Confirm the new pending-interaction lifecycle cleanup releases deferred question/permission promises rather than only hiding stale rows.
  • Check the route-level pruning boundary: service list() remains raw for tests/internal use, while HTTP list routes only return active non-archived sessions.
  • Check the frontend fallback only swallows expected 404s and still surfaces other session warm-up failures.

Risk Notes

  • Pending permission cleanup publishes a reject reply to reuse the existing terminal event shape.
  • No visible UI changes; no screenshots required.
  • No migrations, dependencies, generated files, credentials, or deletion behavior changes.
  • Platform impact is limited to installed app bootstrap/server behavior on all desktop platforms.

How To Verify

opencode targeted tests: 34 passed, 0 failed
  bun test test/question/question.test.ts test/permission-cleanup.test.ts test/session/pending-interaction-lifecycle.test.ts test/server/pending-interaction-routes.test.ts test/server/middleware.test.ts

app bootstrap tests: 11 passed, 0 failed
  bun test src/context/global-sync/bootstrap.test.ts

typecheck: 8/8 packages successful
  bun run typecheck

diff check: no whitespace errors
  git diff --check

Screenshots or Recordings

Not required; this is backend/bootstrap lifecycle behavior with no visible UI surface change.

Checklist

  • Human review status is stated above as pending, approved, or not required
  • I linked the related issue, or stated why there is no issue
  • Label bot should apply type/routing/priority labels; no manual labels were specified per maintainer instruction
  • I described the review focus and any meaningful risks
  • I listed the relevant verification steps and the key result for each
  • I did not introduce unrelated refactors, dependencies, generated files, or file changes beyond the stated scope
  • I manually checked visible UI or copy changes when needed, with screenshots or recordings
  • I considered macOS and Windows impact for platform, packaging, updater, signing, paths, shell, or permissions changes
  • I called out docs, release notes, dependencies, permissions, credentials, deletion behavior, generated content, or local file changes when relevant
  • I reviewed the final diff for unrelated changes and suspicious dependency changes
  • I am targeting dev, and my PR title and commit messages use Conventional Commits in English

Summary by CodeRabbit

  • New Features

    • Pending interactions (permissions, questions, blockers) are now automatically cleared when sessions become inactive, deleted, or archived.
    • Added session liveness detection to identify and clean up "dangling" session entries.
    • New E2E test endpoint for blocker management.
  • Bug Fixes

    • Improved error handling for missing sessions with proper NotFound error detection.
    • Server routes now filter out stale session data before responding.
  • Tests

    • Comprehensive test coverage for session cleanup during deletion and archival.

Review Change Stack

@github-actions github-actions Bot added the app Application behavior and product flows label May 19, 2026
@coderabbitai

coderabbitai Bot commented May 19, 2026

Copy link
Copy Markdown
Contributor

Warning

Rate limit exceeded

@Astro-Han has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 57 minutes and 34 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: ba0fc24c-5109-42cf-99ae-e23f6e43ba81

📥 Commits

Reviewing files that changed from the base of the PR and between cb5c30d and 1a9cd4d.

📒 Files selected for processing (9)
  • .github/workflows/windows-advisory.yml
  • packages/opencode/src/server/instance/blocker.ts
  • packages/opencode/src/server/instance/permission.ts
  • packages/opencode/src/server/instance/question.ts
  • packages/opencode/src/session/liveness.ts
  • packages/opencode/src/session/session.ts
  • packages/opencode/test/github/ci-workflow.test.ts
  • packages/opencode/test/question/question.test.ts
  • packages/opencode/test/server/middleware.test.ts
📝 Walkthrough

Walkthrough

This PR addresses the bug where session-scoped pending interactions (questions, permissions, blockers) outlive their owning sessions, causing repeated 404 errors during app bootstrap. The fix implements cleanup across the session lifecycle, adds filtering to route endpoints, and hardens bootstrap against missing sessions.

Changes

Dangling session cleanup and lifecycle integration

Layer / File(s) Summary
Session liveness and cleanup contracts
packages/opencode/src/session/liveness.ts, packages/opencode/src/session/blocker.ts, packages/opencode/src/permission/index.ts, packages/opencode/src/question/index.ts
SessionLiveness.activeSessionIDs queries non-archived sessions; SessionBlocker.CleanupReason type defined; clearSession methods declared on Permission, Question, and SessionBlocker interfaces.
Core cleanup implementations
packages/opencode/src/session/blocker.ts, packages/opencode/src/permission/index.ts, packages/opencode/src/question/index.ts
SessionBlocker.clearSession maps cleanup reasons to shutdown and removes pending questions; Permission.clearSession removes pending requests and publishes reject replies; Question.clearSession removes questions, publishes rejections with mapped terminal reasons, and fails deferreds with cancelled error.
Session lifecycle integration
packages/opencode/src/session/session.ts
Session.Service layer now depends on Question, Permission, and SessionBlocker; Service.remove and Service.setArchived call clearSession for all three when a session is removed or archived; defaultLayer provides those service layers; minor formatting applied to listGlobal query construction.
Route-level dangling session filtering
packages/opencode/src/server/instance/blocker.ts, packages/opencode/src/server/instance/permission.ts, packages/opencode/src/server/instance/question.ts
GET endpoints compute active session IDs via SessionLiveness, clear inactive sessions via clearSession, and return only active-session entries; E2E endpoint added for blocker upsert (test support).
Bootstrap-level 404 safety
packages/app/src/context/global-sync/bootstrap.ts
isNotFoundError helper detects 404/NotFound errors; warmSessions refactored to return warmed and missing session sets, treating NotFound as missing (no throw); filterGroupedByWarmSessions removes entries for missing sessions; permission/question/blocker bootstrapping filtered before store updates.
Error handling and logging
packages/opencode/src/server/middleware.ts
ErrorMiddleware conditionally logs only non-NotFoundError NamedErrors to prevent NotFoundError responses from cluttering error logs.
Comprehensive test coverage
packages/opencode/test/permission-cleanup.test.ts, packages/opencode/test/question/question.test.ts, packages/opencode/test/server/middleware.test.ts, packages/opencode/test/server/pending-interaction-routes.test.ts, packages/app/src/context/global-sync/bootstrap.test.ts, packages/opencode/test/session/pending-interaction-lifecycle.test.ts
Test suites for Permission/Question/SessionBlocker.clearSession; session lifecycle integration on delete and archive; route-level filtering of dangling sessions; bootstrap handling of missing-session 404s; error middleware logging behavior; includes polling helpers, state creation/cleanup, and runtime management.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • Astro-Han/pawwork#430: Both PRs touch question cancellation semantics in packages/opencode/src/question/index.ts by wiring pending question teardown to RejectedError with cancelled: true; the changes overlap at the shared error/deferred-failure mechanism.

Suggested labels

bug, P1, app, harness

Poem

🐰 Sessions once lingered, now they fade clean,
Questions and blockers no longer unseen,
When sessions depart, their pending state flies,
Bootstrap runs safe, no more 404 cries! 🌿

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 4.76% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'fix(session): clear stale pending interactions' directly summarizes the main change: adding cleanup for session-scoped pending state when sessions are deleted or archived.
Description check ✅ Passed The description covers all required template sections: Summary, Why, Related Issue, Human Review Status, Review Focus, Risk Notes, How To Verify, Screenshots/Recordings, and Checklist with items addressed.
Linked Issues check ✅ Passed The PR addresses all coding requirements from issue #744: session cleanup on delete/archive, list API filtering for missing sessions, frontend bootstrap fallback for 404s, and NotFoundError logging suppression.
Out of Scope Changes check ✅ Passed All changes are directly related to fixing dangling session-scoped pending interactions. No unrelated refactors, dependencies, or file changes were introduced beyond the stated scope.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch pawwork/i744-session-pending-cleanup

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions Bot added harness Model harness, prompts, tool descriptions, and session mechanics P2 Medium priority labels May 19, 2026

@github-actions github-actions 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.

Suggested priority: P2 (includes user-path files (packages/app/src/context/global-sync/bootstrap.test.ts, packages/app/src/context/global-sync/bootstrap.ts)).

P1/P0 are reserved for maintainer confirmation. Please relabel manually if this is a release blocker, security issue, data-loss risk, or updater/runtime failure.

@github-actions

github-actions Bot commented May 19, 2026

Copy link
Copy Markdown

Perf delta summary

Comparator: pass

Profile / Scenario interaction median interaction worst long task max tbt frame gap p95 frame gap max jank count cls status
default / homepage-cold 40 -> 24 (-16) 72 -> 40 (-32) 72 -> 73 (+1) 22 -> 23 (+1) 33.3 -> 33.4 (+0.1) 116.6 -> 116.6 (0) 4 -> 3 (-1) 0 -> 0 (0) pass
default / long-session-input-lag 48 -> 56 (+8) 56 -> 64 (+8) 0 -> 0 (0) 0 -> 0 (0) 16.8 -> 16.8 (0) 16.8 -> 16.8 (0) 0 -> 0 (0) 0 -> 0 (0) pass
default / session-streaming-long 48 -> 48 (0) 72 -> 64 (-8) 0 -> 0 (0) 0 -> 0 (0) 16.8 -> 16.8 (0) 33.4 -> 33.4 (0) 0 -> 0 (0) 0 -> 0 (0) pass
default / tool-call-expand 16 -> 16 (0) 24 -> 24 (0) 0 -> 0 (0) 0 -> 0 (0) 16.8 -> 16.8 (0) 16.8 -> 16.8 (0) 0 -> 0 (0) 0 -> 0 (0) pass
default / tool-default-open-heavy-bash 24 -> 24 (0) 32 -> 32 (0) 65 -> 65 (0) 15 -> 15 (0) 50 -> 50 (0) 166.6 -> 166.7 (+0.1) 3 -> 3 (0) 0 -> 0 (0) pass
default / terminal-side-panel-open 48 -> 56 (+8) 64 -> 56 (-8) 0 -> 0 (0) 0 -> 0 (0) 33.4 -> 33.3 (-0.1) 33.4 -> 33.4 (0) 0 -> 0 (0) 0 -> 0 (0) pass
default / session-scroll-reading 32 -> 32 (0) 56 -> 32 (-24) 0 -> 0 (0) 0 -> 0 (0) 16.7 -> 16.8 (+0.1) 16.7 -> 16.8 (+0.1) 0 -> 0 (0) 0.505 -> 0.505 (0) warn: cls

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request introduces a cleanup mechanism for pending interactions—including permissions, questions, and blockers—to ensure they are terminated when sessions are deleted, archived, or identified as dangling. Key changes include the addition of a clearSession method to core services, the implementation of a SessionLiveness utility for session validation, and updates to the error middleware to suppress logging for NotFoundError. The reviewer recommended refactoring the liveness-based pruning logic into a centralized pruneDangling helper within the SessionLiveness namespace to reduce code duplication and maintain consistency across the API routes.

Comment thread packages/opencode/src/session/liveness.ts
Comment thread packages/opencode/src/server/instance/blocker.ts
Comment thread packages/opencode/src/server/instance/permission.ts
Comment thread packages/opencode/src/server/instance/question.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (3)
packages/opencode/src/server/instance/question.ts (1)

87-100: ⚡ Quick win

Prefer Effect.gen as the top-level composition in this route flow.

This works, but the new route logic is composed via outer .pipe(Effect.flatMap(...)) instead of a single Effect.gen(...) block, which drifts from repo convention.

As per coding guidelines: Use Effect.gen(function* () { ... }) for Effect composition.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/opencode/src/server/instance/question.ts` around lines 87 - 100, The
current route composes effects using svc.list().pipe(Effect.flatMap(...))
instead of using a single Effect.gen; refactor the block to make Effect.gen the
top-level composition: call Effect.gen(function* () { const items = yield*
svc.list(); const active = SessionLiveness.activeSessionIDs(items.map(i =>
i.sessionID)); for (const sessionID of items.filter(i =>
!active.has(i.sessionID)).map(i => i.sessionID)) { yield*
svc.clearSession(sessionID, "dangling_session"); } return items.filter(i =>
active.has(i.sessionID)); }) so you keep the same logic but replace the outer
Effect.flatMap(...) with one Effect.gen(...) using svc.list,
SessionLiveness.activeSessionIDs, and svc.clearSession.
packages/opencode/src/server/instance/permission.ts (1)

110-123: ⚡ Quick win

Use a single Effect.gen composition here to match project Effect style.

The route logic is currently structured as .pipe(Effect.flatMap(...)); please collapse this into Effect.gen(...) composition for consistency with the repo rule.

As per coding guidelines: Use Effect.gen(function* () { ... }) for Effect composition.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/opencode/src/server/instance/permission.ts` around lines 110 - 123,
Replace the current svc.list().pipe(Effect.flatMap(...)) composition with a
single Effect.gen generator: yield the list with const items = yield*
svc.list(), compute active via SessionLiveness.activeSessionIDs(items.map(...)),
build inactiveSessionIDs, loop over them and yield* svc.clearSession(sessionID,
"dangling_session") for each, and finally return items.filter(item =>
active.has(item.sessionID)); this keeps the same behavior but uses Effect.gen
for all Effect composition instead of Effect.flatMap.
packages/opencode/src/server/instance/blocker.ts (1)

43-56: ⚡ Quick win

Align route composition to top-level Effect.gen instead of .pipe(Effect.flatMap(...)).

Behavior is fine, but this new block should follow the repo’s preferred Effect composition style.

As per coding guidelines: Use Effect.gen(function* () { ... }) for Effect composition.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/opencode/src/server/instance/blocker.ts` around lines 43 - 56,
Replace the current .pipe(Effect.flatMap(...)) composition with a top-level
Effect.gen: call svc.list() inside an Effect.gen(function* () { ... }) and
perform the session liveness calculation and loop there (use
SessionLiveness.activeSessionIDs on the yielded items), call
svc.clearSession(sessionID, "dangling_session") for each inactive sessionID, and
return the filtered active items; specifically remove the use of Effect.flatMap
and move the logic that builds inactiveSessionIDs, iterates sessionID, and
invokes svc.clearSession into the body of the top-level Effect.gen so the effect
composition uses Effect.gen rather than .pipe(Effect.flatMap(...)).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/opencode/test/question/question.test.ts`:
- Around line 184-186: The immediate assertion on blocker registration is racy:
after await waitForPending() the blocker created by the question may still be
one tick behind, so change the direct expect(await
listBlockers()).toHaveLength(1) into a wait-based assertion that polls
listBlockers until it returns length 1 (with a short timeout). Locate the code
using waitForPending() and listBlockers() in the test and replace the direct
expect with a retry/wait loop (or call your test-suite's waitFor helper) that
repeatedly calls listBlockers() and asserts length === 1 before failing.

In `@packages/opencode/test/server/middleware.test.ts`:
- Around line 71-102: Tests in middleware.test.ts currently assert against the
entire log file (using readLogFile()) which can include unrelated pre-existing
lines; change both tests to capture the log contents immediately after
Log.init() (or record a baseline via readLogFile()) and then read the log file
again after the request, compute the delta/new lines produced by the request,
and run the expect assertions against that delta only (referencing
readLogFile(), Log.init(), ErrorMiddleware and the "/missing" and "/boom"
request flows) so the assertions only consider request-local log output.

---

Nitpick comments:
In `@packages/opencode/src/server/instance/blocker.ts`:
- Around line 43-56: Replace the current .pipe(Effect.flatMap(...)) composition
with a top-level Effect.gen: call svc.list() inside an Effect.gen(function* () {
... }) and perform the session liveness calculation and loop there (use
SessionLiveness.activeSessionIDs on the yielded items), call
svc.clearSession(sessionID, "dangling_session") for each inactive sessionID, and
return the filtered active items; specifically remove the use of Effect.flatMap
and move the logic that builds inactiveSessionIDs, iterates sessionID, and
invokes svc.clearSession into the body of the top-level Effect.gen so the effect
composition uses Effect.gen rather than .pipe(Effect.flatMap(...)).

In `@packages/opencode/src/server/instance/permission.ts`:
- Around line 110-123: Replace the current svc.list().pipe(Effect.flatMap(...))
composition with a single Effect.gen generator: yield the list with const items
= yield* svc.list(), compute active via
SessionLiveness.activeSessionIDs(items.map(...)), build inactiveSessionIDs, loop
over them and yield* svc.clearSession(sessionID, "dangling_session") for each,
and finally return items.filter(item => active.has(item.sessionID)); this keeps
the same behavior but uses Effect.gen for all Effect composition instead of
Effect.flatMap.

In `@packages/opencode/src/server/instance/question.ts`:
- Around line 87-100: The current route composes effects using
svc.list().pipe(Effect.flatMap(...)) instead of using a single Effect.gen;
refactor the block to make Effect.gen the top-level composition: call
Effect.gen(function* () { const items = yield* svc.list(); const active =
SessionLiveness.activeSessionIDs(items.map(i => i.sessionID)); for (const
sessionID of items.filter(i => !active.has(i.sessionID)).map(i => i.sessionID))
{ yield* svc.clearSession(sessionID, "dangling_session"); } return
items.filter(i => active.has(i.sessionID)); }) so you keep the same logic but
replace the outer Effect.flatMap(...) with one Effect.gen(...) using svc.list,
SessionLiveness.activeSessionIDs, and svc.clearSession.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 66c1910f-0784-42f8-9bf7-341f75aa9c22

📥 Commits

Reviewing files that changed from the base of the PR and between e547fbc and cb5c30d.

📒 Files selected for processing (16)
  • packages/app/src/context/global-sync/bootstrap.test.ts
  • packages/app/src/context/global-sync/bootstrap.ts
  • packages/opencode/src/permission/index.ts
  • packages/opencode/src/question/index.ts
  • packages/opencode/src/server/instance/blocker.ts
  • packages/opencode/src/server/instance/permission.ts
  • packages/opencode/src/server/instance/question.ts
  • packages/opencode/src/server/middleware.ts
  • packages/opencode/src/session/blocker.ts
  • packages/opencode/src/session/liveness.ts
  • packages/opencode/src/session/session.ts
  • packages/opencode/test/permission-cleanup.test.ts
  • packages/opencode/test/question/question.test.ts
  • packages/opencode/test/server/middleware.test.ts
  • packages/opencode/test/server/pending-interaction-routes.test.ts
  • packages/opencode/test/session/pending-interaction-lifecycle.test.ts

Comment thread packages/opencode/test/question/question.test.ts
Comment thread packages/opencode/test/server/middleware.test.ts
@Astro-Han Astro-Han added the bug Something isn't working label May 19, 2026
@github-actions github-actions Bot added ci Continuous integration / GitHub Actions task Narrow execution, audit, spike, migration, tracking, or upstream follow-up work labels May 19, 2026
@Astro-Han Astro-Han removed the task Narrow execution, audit, spike, migration, tracking, or upstream follow-up work label May 19, 2026
@github-actions github-actions Bot added the task Narrow execution, audit, spike, migration, tracking, or upstream follow-up work label May 19, 2026
@Astro-Han Astro-Han removed the bug Something isn't working label May 19, 2026
@Astro-Han

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 19, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Astro-Han added a commit that referenced this pull request May 19, 2026
* docs(github): tighten PR and task templates against agent misuse

PR #748 surfaced a template ambiguity: the labeler bot auto-applied
routing/priority labels but not the required type label, the agent
rewrote the checklist text to "Label bot should apply type/routing/
priority labels; no manual labels were specified per maintainer
instruction" instead of adding the missing `bug` label, and the human
maintainer had to add `bug` minutes later before validation ran.

Five rounds of crosscheck (Claude Opus + Codex) found and addressed:
- Label checklist conflated bot-applied vs author-applied labels and
  had an "or I requested maintainer labeling" escape hatch.
- All checklist items were first-person past-tense assertions with no
  explicit immutability guard; the agent treated the lines as editable.
- Human Review Status was a free-text contract with a loose
  "or not required" escape hatch.
- How To Verify example block had no machine-spottable marker; an
  agent could leave the example verbatim.
- Task template Execution mode options had overlapping prose and
  uneven parallelism.

The new PR template splits labels into three explicit author/bot rows,
adds a top-of-file policy comment plus a "How to use this checklist"
blockquote, converts Human Review Status into a strict three-option
enum, adds a `replace-before-submit` HTML sentinel to the example
block, and tags genuinely conditional items with **(conditional)**.

The new Task template Execution mode rewrites each option as an
explicit declarative directive ("the agent must not... until..." /
"the agent must post the plan as an issue comment..." / "the agent
makes the requested changes... must not push directly to dev").

Round-5 crosscheck returned "None" for both code findings and design
alternatives from both reviewers. Remaining design-level work (CI
lint enforcement, issue-template `area` dropdown restructure) is
deferred to a follow-up PR.

* ci(labeler): route all .github/ changes to ci, not only workflows

Templates and issue forms under .github/ITS_TEMPLATE/ and the top-level
PR template are CI/process infrastructure that should route the same
way as workflow files. Without this, a PR that only touches
.github/pull_request_template.md or .github/ISSUE_TEMPLATE/*.yml
receives no routing label from the labeler bot, and the manual
override is stripped by sync-labels on the next pr-triage run.

The task rule keeps the narrower .github/workflows/** scope: task is
a type label, and per the updated PR template, type labels are
author-applied, not bot-applied. Workflow PRs retain the existing
task auto-application as a historical convenience; this can be
revisited in a follow-up if the inconsistency proves confusing.

* ci(labeler): keep .github/workflows/** explicit in ci rule

Restore the explicit .github/workflows/** glob alongside the broader
.github/** glob. The pr-triage contract test at
packages/opencode/test/github/pr-triage-workflow.test.ts:57 uses
literal-string matching to assert that workflow files are routed to
the ci label, so dropping the workflows glob broke the test even
though .github/** subsumes it semantically.

Keeping both globs preserves the test contract and documents the
intent that workflow files are first-class CI infra while other
.github/ files (templates, labeler.yml itself, dependabot config)
are CI process.
@Astro-Han
Astro-Han merged commit 54856f0 into dev May 19, 2026
26 of 28 checks passed
@Astro-Han
Astro-Han deleted the pawwork/i744-session-pending-cleanup branch May 19, 2026 06:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

app Application behavior and product flows ci Continuous integration / GitHub Actions harness Model harness, prompts, tool descriptions, and session mechanics P2 Medium priority task Narrow execution, audit, spike, migration, tracking, or upstream follow-up work

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] Dangling session-scoped pending interactions trigger session 404 bootstrap errors

1 participant