Skip to content

fix(workspace): attach the engine for a message sent while the assistant is busy - #1461

Open
ralphstodomingo wants to merge 3 commits into
mainfrom
fix/engine-attach-on-queued-message
Open

ralphstodomingo wants to merge 3 commits into
mainfrom
fix/engine-attach-on-queued-message

Conversation

@ralphstodomingo

@ralphstodomingo ralphstodomingo commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

Issue for this PR

Closes #1460

Type of change

  • Bug fix

What does this PR do?

A message sent while the assistant is busy joins the running prompt loop instead of starting one. The engine's turn boundary (reconcile the engine, then catalog and pin the tools) ran only on a loop's first catalog, so that message kept the run's tools and an engine installed meanwhile never attached for it.

The boundary now runs on the first catalog of each user request in the loop, not of each user message. The loop writes user messages itself: the summary after a subtask, the validator retry, the compaction marker and the continue message. Re-running the boundary on those would re-pin engine tools mid-task, which the pin exists to prevent.

Precedent. What counts as a user request isn't new here. Lesson retrieval in the same loop already decides it (the lessons block before the tool catalog in prompt.ts): a user message with a text part that is neither synthetic nor ignored, or a file part; a compaction replay stamped with metadata.learnOriginalMessage stays the request it replays. This PR moves that rule unchanged into UserRequest.requestID and both callers use it, so the two can't drift apart.

TurnBoundary.tracker() replaces the catalogued flag. It runs the boundary on the loop's first catalog and on the first catalog after a request it hasn't seen. It checks every request in history, not just the newest, so neither a loop-written message nor a replay arriving after a queued one hides it.

Claims

  • C1 A message sent while the assistant is busy gets its own turn boundary in the same loop, so an engine installed meanwhile attaches on it.
  • C2 The messages the loop writes itself never run the boundary again.
  • C3 Lesson retrieval selects as before: same rule, now shared.
  • C4 A loop with one request is unchanged: one boundary, on its first catalog.

Residuals

  • R1 Compaction stamps a replay only while lessons are delivered for the session (projects with .altimate-code/learn). Elsewhere, a replay after an overflow counts as a new request and runs the boundary once more, where the request restarts from the summary. With the engine unchanged, that reconcile changes nothing.
  • R2 The turn that raises the install offer still runs without integration tools. That's a separate design question.
  • R3 A client that supplies its own message ids out of send order: a message given a lower id than the one running sorts before it, and the running loop ends without answering it (on main too).

Overlap: #1431 adds if (firstCatalog) workspaceNotice.settle(sessionID) on a line this PR renames. Whichever merges second resolves it as if (boundary) …, so the linked-project notice also re-settles for a queued request.

How did you verify your code works?

  • The rule, over each writer's message shape: user text, a file, subtask summary, validator retry, compaction marker, continue message, stamped and unstamped replays.
  • The tracker, over loop histories, including a queued request followed by a loop-written message.
  • The real prompt loop (test LLM server, boundary spied): a message sent while the first answer is on hold reaches the model in the same run and gets a second boundary. On main this test fails (1 boundary, expected 2). An overflow that compacts and continues gets one.
  • Live before/after (E2E), install mid-run then a queued message: main gets no engine tools; here the engine starts with its 20 tools.
  • Typecheck clean; learn, workspace and session suites pass (4183, 45 todo). Marker Guard clean.

Codex rounds against these claims: review log.

Screenshots / recordings

Not a UI change.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

🤖 Generated with Claude Code

https://claude.ai/code/session_01HRUhVhg6XwxSKJs1iTufiA


Summary by cubic

Fixes the workspace engine's turn boundary so a message sent while the assistant is busy attaches the engine on that message, instead of keeping the tools from the previous request.

  • The boundary now runs on the first catalog of each user request in the loop, not just the loop's first catalog.
  • The rule for identifying user requests is now shared with lesson retrieval via UserRequest.requestID.
  • Any request not seen before in the history triggers a boundary, so a stamped compaction replay or out-of-order history can't hide a message queued during compaction.
  • The loop's own messages (subtask summary, validator retry, compaction marker, continue message) still don't trigger a boundary.

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

View guided diff Turn on auto-fix

Summary by CodeRabbit

  • Bug Fixes
    • Workspace updates and notices now run at each new user-request boundary, including requests submitted while the assistant is busy.
    • Compaction and continuation remain part of the same request turn, avoiding duplicate boundary handling.

@ralphstodomingo ralphstodomingo self-assigned this Oct 13, 2026
@coderabbitai

coderabbitai Bot commented Oct 13, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 374d806f-ec42-4bd9-99ce-ce39b5d5c27c
📥 Commits

Reviewing files that changed from the base of the PR and between d0f917b and bed0007.

📒 Files selected for processing: 6
  • packages/opencode/src/altimate/session/user-request.ts
  • packages/opencode/src/altimate/workspace/turn-boundary.ts
  • packages/opencode/src/session/prompt.ts
  • packages/opencode/test/altimate/session/user-request.test.ts
  • packages/opencode/test/altimate/workspace/turn-boundary.test.ts
  • packages/opencode/test/session/workspace-turn-boundary-loop.test.ts

Included review availability: This review used your included allowance. Your plan provides up to 4 included reviews per hour; 0 remain after this review.

📝 Walkthrough

The prompt loop now detects user-request boundaries across catalogs. It runs workspace boundary operations for each new request and uses shared request identity logic for learning selection. Tests cover request identification, tracking, queued messages, and compaction continuation.

Changes: Workspace request boundaries

Layer / File(s) Summary
Request identity and boundary tracking
packages/opencode/src/altimate/session/user-request.ts, packages/opencode/src/altimate/workspace/turn-boundary.ts, packages/opencode/test/altimate/session/user-request.test.ts, packages/opencode/test/altimate/workspace/turn-boundary.test.ts
requestID identifies eligible user requests by their replay metadata or message ID. tracker reports the first catalog and catalogs with unseen request IDs. Unit tests cover both behaviors.
Prompt-loop boundary integration
packages/opencode/src/session/prompt.ts, packages/opencode/test/session/workspace-turn-boundary-loop.test.ts
The prompt loop runs workspace reconciliation, cataloguing, tool pinning, and notice settlement at request boundaries. Learning selection uses requestID. Integration tests cover a queued message and compaction continuation.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix · Severity of issue fixed: Medium

Sequence Diagram(s)

sequenceDiagram
  actor User
  participant SessionPrompt
  participant TurnBoundary
  participant WorkspaceEngine
  User->>SessionPrompt: Submit a message while the loop is running
  SessionPrompt->>TurnBoundary: Check the catalog message history
  TurnBoundary-->>SessionPrompt: Report a boundary for a new request ID
  SessionPrompt->>WorkspaceEngine: Reconcile, catalog, and pin tools
Loading
Merge Risk: ⚪ Minimal · up to bed00

The change makes the workspace engine attach for messages queued while the assistant is busy. No concrete merge-blocking issue was established in this review.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 60.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 5 functions across 6 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Title check Passed The title clearly and concisely describes the main change: attaching the workspace engine for a message sent while the assistant is busy.
Description check Passed The description includes the issue, change type, detailed implementation rationale, verification results, residuals, screenshots status, and completed checklist items.
Linked Issues check Passed The PR satisfies #1460. UserRequest.requestID identifies real user requests, and TurnBoundary.tracker runs the workspace engine boundary for the first catalog after each unseen request in the runn…
Out of Scope Changes check Passed The changes stay within #1460. The new request classifier, tracker, prompt-loop integration, focused tests, and real-loop regression test directly support correct engine attachment for queued messages…
  • Fix all pre-merge checks with AI
✨ Finishing Touches: 💡 1
📝 Generate docstrings: 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

A rabbit checks each request in line,
New IDs mark a boundary sign.
The workspace tools join the flow,
While queued messages wait to go.
Through compaction, one turn stays,
The rabbit hops through tidy arrays.

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

@ralphstodomingo

ralphstodomingo commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor Author

Codex review log

Contract: claims C1–C4 and residuals R1–R2 in the PR description. Up to 3 rounds; a round with no claim violation ends review.

Round Head Result
1 7ff898562 1 P1, fixed in bf485dc6e: the newest request is picked by message id, not array position, since filterCompacted reorders history after a tail-keeping compaction. thread
2 bf485dc6e 1 P2, declined with evidence and recorded as R3: with client ids out of send order the running loop never answers the lower-id message, on main too, so its boundary is moot. thread. Every item fixed or declined: no push, no round 3.
3 (confirming, past the cap, OK'd by Ralph) 16d49697d Clean: "Didn't find any major issues."

cubic, first run after the ready flip, on bf485dc6e: 1 P1 fixed in 16d49697d (the tracker checks every request in history, not only the newest, so a stamped replay can't hide a queued request; this also covers round 1's reordering), 1 P2 test fix taken, 1 P2 declined on its thread. 16d49697d has no Codex round yet (cap reached).

cubic, second run, on 16d49697d: clean (0 issues). Kilo: 1 test-only note answered on its thread.

@ralphstodomingo

Copy link
Copy Markdown
Contributor Author

@codex review against the numbered claims (C1–C4) and the disclosed residuals (R1–R2) in this PR's description: report only a reproducible trace that violates a numbered claim. Instances of the disclosed residuals are not findings. A round with no claim violation ends 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: 7ff8985620

ℹ️ 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 packages/opencode/src/altimate/session/user-request.ts Outdated
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 13, 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-13T07:21:23.833482Z 16d4969 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.

@ralphstodomingo

Copy link
Copy Markdown
Contributor Author

@codex review against the numbered claims (C1–C4) and the disclosed residuals (R1–R2) in this PR's description: report only a reproducible trace that violates a numbered claim. Instances of the disclosed residuals are not findings. The push since round 1 (bf485dc) changes only latestRequestID to pick the newest request by message id. A round with no claim violation ends 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: bf485dc6e3

ℹ️ 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 packages/opencode/src/altimate/session/user-request.ts Outdated
@ralphstodomingo

Copy link
Copy Markdown
Contributor Author

E2E: before and after, the same steps

Setup: a fresh project linked to a test workspace that declares Snowflake, Altimate, Jira and GitHub (60 tools); no datamate on PATH; isolated state; run from source; Claude Sonnet 4.5.

Steps: send Run the bash command sleep 45 and then reply with the single word: done → the install offer appears → Install now → "Workspace engine installed" after ~15 s, with the sleep still running → send List every tool name you have that starts with datamate_, one per line. If you have none, say: NO DATAMATE TOOLS, which shows as QUEUED.

main (b093196877): the queued message runs in the same loop without the engine.

┃  List every tool name you have that starts with datamate_, one per line. If you have none, say: NO DATAMATE TOOLS
     NO DATAMATE TOOLS
     done

No engine process was started.

This PR (bf485dc6e): the queued message gets its own boundary, and the engine attaches on it.

┃  List every tool name you have that starts with datamate_, one per line. If you have none, say: NO DATAMATE TOOLS
     datamate_ask_knowledge_base
     datamate_altimate_analyze_snowflake_query
     … (Altimate 7, Jira 8, Snowflake 5)
     datamate_snowflake_get_table_stats
     done

datamate start-stdio --datamate 5 is running, and the boot box reads "20 of 60 integration tools available · 40 need attention" (the account has no GitHub connection, so GitHub's 40 are expected to be missing).

@ralphstodomingo
ralphstodomingo marked this pull request as ready for review October 13, 2026 06:24

@cubic-dev-ai cubic-dev-ai 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.

All reported issues were addressed across 6 files

Reply with feedback, questions, or to request a fix.

View guided diff | Turn on auto-fix | Re-trigger cubic

Comment thread packages/opencode/src/altimate/workspace/turn-boundary.ts Outdated
Comment thread packages/opencode/src/altimate/session/user-request.ts
Comment thread packages/opencode/test/session/workspace-turn-boundary-loop.test.ts
export function requestID(message: MessageV2.WithParts): string | undefined {
if (message.info.role !== "user") return undefined
const asked = message.parts.some(
(part) => (part.type === "text" && !part.synthetic && !part.ignored) || part.type === "file",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

WARNING: Count subtask-only commands as user requests for the turn boundary

The built-in /review command has subtask: true (command/index.ts) and SessionPrompt.command() saves it as a user message containing only a subtask part. If it is queued while request A is busy, the running loop executes the subtask and then writes a synthetic summary; neither message passes this text-or-file check. latestRequestID() still returns A, so the next catalog skips atTurnStart() and the command's parent continuation keeps A's engine and tool pin, even when an engine was installed between requests. The tracker needs to recognize a user-authored subtask as a new boundary without treating the loop-written summary as one; the queued-subtask test currently models /review as ordinary text.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

@kilo-code-bot

kilo-code-bot Bot commented Oct 13, 2026 •

Copy link
Copy Markdown

Code Review Summary

Status: 1 Issue Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
packages/opencode/src/altimate/session/user-request.ts 18 Subtask-only commands such as /review are saved with only a subtask part, which requestID does not recognize, so a subtask queued while the assistant is busy never runs the turn boundary and its parent continuation keeps the previous engine/tool pin.
Files Reviewed (6 files)
  • packages/opencode/src/altimate/session/user-request.ts - 1 issue
  • packages/opencode/src/altimate/workspace/turn-boundary.ts - 0 issues
  • packages/opencode/src/session/prompt.ts - 0 issues
  • packages/opencode/test/altimate/session/user-request.test.ts - 0 issues
  • packages/opencode/test/altimate/workspace/turn-boundary.test.ts - 0 issues
  • packages/opencode/test/session/workspace-turn-boundary-loop.test.ts - 0 issues

Fix these issues in Kilo Cloud

Previous Review Summaries (2 snapshots, latest commit 16d4969)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit 16d4969)

Status: 3 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 3
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
packages/opencode/src/altimate/session/user-request.ts 18 Subtask-only commands such as /review remain unrecognized as queued requests, so their parent continuation keeps the previous engine pin (previously commented).
packages/opencode/src/altimate/session/user-request.ts 23 Caller-controlled replay metadata can make a new request appear already seen (previously commented).
packages/opencode/test/session/workspace-turn-boundary-loop.test.ts 158 A failed queued-message assertion leaves the test LLM response held and can hang cleanup (new finding, inline comment posted).
Files Reviewed (6 files)
  • packages/opencode/src/altimate/session/user-request.ts - 2 issues
  • packages/opencode/src/altimate/workspace/turn-boundary.ts - 0 issues
  • packages/opencode/src/session/prompt.ts - 0 issues
  • packages/opencode/test/altimate/session/user-request.test.ts - 0 issues
  • packages/opencode/test/altimate/workspace/turn-boundary.test.ts - 0 issues
  • packages/opencode/test/session/workspace-turn-boundary-loop.test.ts - 1 issue

Fix these issues in Kilo Cloud

Review was read-only; tests were not executed.

Previous review (commit bf485dc)

Status: 4 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 1
WARNING 3
SUGGESTION 0
Issue Details (click to expand)

CRITICAL

File Line Issue
packages/opencode/src/altimate/workspace/turn-boundary.ts 24 A newer stamped compaction replay can hide a queued request from the turn boundary (already commented).

WARNING

File Line Issue
packages/opencode/src/altimate/session/user-request.ts 18 Subtask-only commands such as /review are not recognized as queued requests, so their parent continuation keeps the previous engine pin (new finding).
packages/opencode/src/altimate/session/user-request.ts 23 Caller-controlled replay metadata can make a new request appear already seen (already commented).
packages/opencode/test/session/workspace-turn-boundary-loop.test.ts 157 The integration test does not assert the queued message was saved before releasing the held response (already commented).
Files Reviewed (6 files)
  • packages/opencode/src/altimate/session/user-request.ts - 2 issues
  • packages/opencode/src/altimate/workspace/turn-boundary.ts - 1 issue
  • packages/opencode/src/session/prompt.ts - 0 issues
  • packages/opencode/test/altimate/session/user-request.test.ts - 0 issues
  • packages/opencode/test/altimate/workspace/turn-boundary.test.ts - 0 issues
  • packages/opencode/test/session/workspace-turn-boundary-loop.test.ts - 1 issue

Fix these issues in Kilo Cloud

Review was read-only; tests were not executed.


Reviewed by deepseek-pro-latest · Input: 69K · Output: 24.7K · Cached: 1.1M

Review guidance: REVIEW.md from base branch main

Comment thread packages/opencode/test/session/workspace-turn-boundary-loop.test.ts
@ralphstodomingo

Copy link
Copy Markdown
Contributor Author

@codex review — confirming round, scoped to the push since your last round (bf485dc..16d4969: the tracker runs the boundary for any request it has not seen, not only the newest, and a test assertion). Review only that change, against the numbered claims (C1–C4) and the disclosed residuals (R1–R3) in this PR's description: report only a reproducible trace in which that change violates a numbered claim. Instances of the disclosed residuals are not findings. A round with no claim violation ends review.

@chatgpt-codex-connector

Copy link
Copy Markdown

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

Reviewed commit: 16d49697d0

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

@sahrizvi

Copy link
Copy Markdown
Collaborator

Consensus Code Review — altimate-code PR #1461

fix(workspace): attach the engine for a message sent while the assistant is busy (head 16d49697d0)

Code Review Summary

Verdict: APPROVE (no blockers; minor follow-ups)
Critical Issues: 0
Major Issues: 0
Minor Issues: 3
Design notes (documented trade-offs): 2
Nits: 2

Claims verified by the whole panel:

  • C1: a queued text or file message gets its own boundary.
  • C2: none of the loop-written messages carries a request (requestID is undefined for each): the subtask summary (prompt.ts:~1101-1122), the validator retry (~1997-2014), the compaction marker and the continue message (compaction.ts:~1779).
  • C3: requestID is a faithful move of the lessons predicate. The text/file query is now built lazily inside if (!selected), which is equivalent.
  • C4: a single-request loop gets one boundary, on its first catalog.

Minor Issues

  1. A queued subtask slash command never runs the boundary (Logic): packages/opencode/src/altimate/session/user-request.ts:17-20, packages/opencode/src/session/prompt.ts:4225-4239
    With isSubtask, SessionPrompt.command writes a user message whose only part is type: "subtask". requestID returns undefined for it, so a /review-style subtask command sent while the assistant is busy is invisible to the tracker. The child session gets its own boundary. The parent's continuation after the synthetic summary still keeps the previously pinned engine tools, so C1 doesn't hold for this message shape. The test "runs for a queued message even when the loop writes one after it" models /review with a subtask as a plain text message, which is not what the command path writes.
    Fix: treat a subtask part as a request in the tracker, or document it as residual R4. Either way, make the test fixture match the real message shape.
    Flagged by: Claude; confirmed by DeepSeek V4 Pro, Qwen 3.6 Plus and GPT 5.3 Codex in convergence

  2. The tracker rescans the full history on every catalog (Performance): packages/opencode/src/altimate/workspace/turn-boundary.ts:24-30
    The cost is O(messages × parts) per catalog. In practice that's negligible next to filterCompacted and the reminders. Optionally, cache each message's classification by info.id. Short-circuiting on the first unseen request is not safe: every unseen request has to be added to seen, or the next catalog fires again.
    Flagged by: GPT 5.3 Codex, Grok 4.3, Qwen 3.6 Plus, DeepSeek V4 Pro, Claude

  3. Missing loop-level tests (Testing): packages/opencode/test/session/workspace-turn-boundary-loop.test.ts
    The real-loop tests only exercise the queued message and overflow with compaction. Still missing through the real loop:

    • validator retry and subtask summary, expecting a single boundary;
    • an unstamped replay without lessons, expecting one extra boundary (R1);
    • a queued subtask-only command (issue 1);
    • two requests queued before one catalog.
      Flagged by: GPT 5.3 Codex, DeepSeek V4 Pro, Qwen 3.6 Plus, Claude

Design notes (documented trade-offs, not defects)

  • D1: a mid-loop boundary re-pins tool order and can re-link the directory engine. Locations: prompt.ts:1459-1461, engine-overlay.ts:472-483.
    • Tool order: with boundary === true, pinTurnTools discards the previous key order. If the catalog order differs, the prompt cache misses for the rest of the loop.
    • Engine re-link: atTurnStart → reconcile may re-link the per-directory engine. Another session in the same directory with pinned wrappers then calls a closed client.
    • Both were previously reachable only at loop start. They are now reachable on every queued message. Worth a line in the PR residuals. Claude; reclassified by GPT 5.3 Codex
  • D2: R1, an unstamped compaction replay re-runs the boundary mid-task. Locations: turn-boundary.ts:15-17, compaction.ts:1667-1675.
    • Without lessons (most projects), each overflow compaction with a replay re-runs the boundary. If the engine changed meanwhile, that's a mid-task engine switch.
    • The PR documents this as intended.
    • Possible follow-up: the stamp is metadata only, so the original id could be stamped unconditionally under a neutral key. Request identity would then no longer depend on the lessons feature. Claude; reclassified by GPT 5.3 Codex

Nits

  • user-request.ts:19: FilePart has no synthetic/ignored flags, so any file part counts as a request. Add a comment that loop-written messages must not carry file parts. Qwen 3.6 Plus (downgraded from MAJOR)
  • workspace-turn-boundary-loop.test.ts:~148-158: the test waits for the queued message by polling 100×20ms. That's fine, but a diagnostic when the poll runs out would help if it flakes under load. Qwen 3.6 Plus

Positive Observations

  • One source of truth for "is this a user request", so lessons and the engine boundary can't drift apart.
  • The tracker scans all of history, so it handles filterCompacted reordering and stamped replays that arrive after a queued message. Both cases are tested.
  • A real-loop integration test that fails on main.
  • One tracker closure per loop, with no module-level state.
  • Comments explain the why (loop step vs. catalog, reordering).

Unintended Consequences

  1. The engine pin and reconcile now run mid-loop: prompt.ts:1459-1461. This can reset tool order (prompt-cache miss) and may re-link the engine under other sessions in the same directory (D1). Mitigation: document it in the residuals. Claude
  2. Overlap with feat(workspace): turn off datamate_manager in projects linked to a workspace #1431: the firstCatalog rename. This is a merge-order conflict only, already noted in the PR.

Rejected panel findings

  • "Lesson retrieval reads user before insertReminders mutates it" (DeepSeek, MAJOR): rejected. The ordering is unchanged from main, lessons run before reminders on purpose, and requestID ignores synthetic parts.
  • "pinTurnTools is now called on every catalog" (DeepSeek): rejected. Main already called it on every catalog.
  • "Short-circuit the tracker on the first unseen request" (Grok's fix suggestion): rejected because it would re-fire on the next catalog.
  • Local requestID shadowing, redundant String() (DeepSeek, Qwen): rejected. This is pre-existing code moved verbatim.
  • File-level header comments (Grok): rejected, since the repo marker convention is followed.

Finding Attribution

Issue Origin Type
Queued subtask-only command (type: "subtask" part) gets no boundary; the test fixture models it as text Claude Unique (confirmed in convergence)
tracker() rescans full history per catalog GPT 5.3 Codex, Grok 4.3, Qwen 3.6 Plus, DeepSeek V4 Pro, Claude Consensus
Missing real-loop tests (validator, subtask summary, unstamped replay, subtask command) GPT 5.3 Codex, DeepSeek V4 Pro, Qwen 3.6 Plus, Claude Consensus
D1: mid-loop re-pin (cache miss) and re-link under concurrent sessions Claude Convergence fix (MINOR → design note, per GPT 5.3 Codex)
D2: R1 unstamped replay re-runs the boundary; stamp unconditionally Claude Convergence fix (MINOR → design note, per GPT 5.3 Codex)
FilePart lacks synthetic flag Qwen 3.6 Plus Unique (downgraded MAJOR → NIT)
Test polling without diagnostic Qwen 3.6 Plus Unique

Reviewed by 5 participants: Claude, GPT 5.3 Codex, DeepSeek V4 Pro, Grok 4.3, Qwen 3.6 Plus. GLM-5.2 was dropped mid-run on the user's instruction (relayed by a peer session) and replaced with Qwen 3.6 Plus. Convergence: 1 round. DeepSeek, Grok and Qwen approved. GPT asked for a reclassification, which was incorporated.

sahrizvi
sahrizvi previously approved these changes Oct 13, 2026

@sahrizvi sahrizvi 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.

Verdict: approve with comments. No critical or major findings. The minor findings and nits are in the consensus review comment; please address them here or in a follow-up.

ralphstodomingo and others added 3 commits October 14, 2026 12:54
…ant is busy

Such a message joins the running prompt loop, and the engine's turn boundary ran only on a loop's first catalog. It now runs on the first catalog of each user request, counted by lesson retrieval's rule (moved into `UserRequest.requestID`), so the loop's own messages keep the turn's pin.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HRUhVhg6XwxSKJs1iTufiA
After a compaction that keeps a tail, the loop's history is not in id order (`filterCompacted` places the summary after the retained tail), so a positional scan could pick the retained request and skip a message queued during the compaction. Same rule as `MessageV2.latest`.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HRUhVhg6XwxSKJs1iTufiA
…y the newest

A stamped compaction replay is newest by id but maps back to a request already seen, so checking only the newest could hide a message queued during the compaction. Every request in history is checked now, which also makes the order of history irrelevant.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HRUhVhg6XwxSKJs1iTufiA
@ralphstodomingo

Copy link
Copy Markdown
Contributor Author

@sahrizvi, this needs your re-approval: rebasing onto main after #1431 and #1464 merged dismissed it.

The only change from 16d49697d is the prompt.ts conflict with #1431, the overlap your review noted:

  • both imports kept;
  • workspaceNotice is declared beside turnBoundary;
  • if (firstCatalog) workspaceNotice.settle(sessionID) became if (boundary) workspaceNotice.settle(sessionID), so the linked-project notice settles at each boundary, a queued request's included.

Compare: git range-diff b093196877..16d49697d0 d0f917b5c2..bed0007399. Typecheck and the workspace, turn-boundary and loop suites pass on the rebased tree; CI is running on bed0007399.

The minors from your review go in one follow-up PR, after this merges.

This branch has not been deployed

No deployments
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.

Workspace engine never attaches for a message sent while the assistant is busy

2 participants