Skip to content

Add progressive Hub workspace affinity - #3994

Closed
michaelmwu wants to merge 27 commits into
getpaseo:mainfrom
michaelmwu:workspace-affinity-20260829
Closed

michaelmwu wants to merge 27 commits into
getpaseo:mainfrom
michaelmwu:workspace-affinity-20260829

Conversation

@michaelmwu

@michaelmwu michaelmwu commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Linked issue

Companion Hub change: getpaseo/hub#86. There is no standalone issue.

Type of change

  • Bug fix
  • New feature
  • Enhancement
  • Refactor
  • Docs

Reasoning

A Hub workflow responding to multiple messages in one Slack thread, Discord thread, GitHub issue, or GitHub pull request should be able to keep using the checkout created for that conversation. Hub can provide a stable custom affinity key, but the Paseo daemon owns the actual workspace, worktree, agent records, restoration path, and archive operation.

This PR adds the optional daemon-side capability needed for exact reuse while keeping deployment progressive. Existing Hub versions never send the field. A new Hub talking to an older daemon accepts the missing acknowledgement and gets the existing fresh-workspace behavior, so operators do not need to update every daemon before updating Hub.

Usage

In the trigger form, open Workspace affinity under Where it runs and enter a custom key. Empty disables reuse. The equivalent complete single-run trigger is:

name: linear-triage
on:
  linear.comment_created:
    connection: company-linear
    filters:
      from_users: [your-linear-user-id]
run:
  target: { daemon: build-server, cwd: /workspace/project }
  agent: { provider: codex, mode: full-access }
  max_runtime: 2h
  idle_timeout: 10m
  auto_archive: true
  workspace_affinity:
    key: "triage:${{ paseo.trigger.conversation_key }}"
  prompt: |
    Handle this request: ${{ paseo.prompt }}
    Use hub.reply for your response, then call hub.finish_execution.

Legacy bundles put workspace_affinity on a step. The complete usage reference is Workspace affinity, updated alongside Hub's single-run editor and Linear issue support. Linear Agent Sessions remain a separate Hub integration; issue identity should select the workspace while session identity controls replies and stop signals.

The key is custom: it may be a literal, a finite authored expression, or a prefix plus the provider-authenticated paseo.trigger.conversation_key. Hub sends the daemon:

{
  "workspaceAffinity": {
    "key": "review:<opaque authenticated conversation key>",
    "retainUntil": "<workflow max_runtime deadline>",
    "autoArchive": true
  }
}

A supporting daemon acknowledges successful binding with workspaceAffinityApplied: true. It hashes the raw key, reuses or restores the mapped workspace, and extends retention to the latest matching workflow deadline. idle_timeout remains the liveness deadline for one execution; it does not define the gap between executions. This lets an agent auto-archive after finishing while its workspace stays reusable until the retained workflow deadline.

Disconnecting or revoking the Hub relationship fences new execution authority but does not abandon an already acknowledged retention deadline. The daemon keeps those cleanup timers independently and reconstructs them from persisted mappings after restart.

Why the daemon change is necessary

Hub can select the affinity key and deadline, but it cannot safely own daemon-local workspace lifecycle. Only the daemon can:

  • atomically map an opaque key to one of its local workspace IDs
  • create or restore the exact workspace and cwd
  • persist and recover the mapping across daemon restarts and Hub reconnects
  • verify that future requests keep the same cwd, worktree target, and auto-archive policy
  • atomically exclude new registrations while checking for unrelated live agents and archiving a shared workspace
  • run and retry the local archive timer after relationship disconnect or revocation

Trying to do this with only Hub changes would require Hub to discover and persist private daemon-local workspace IDs, would not restore an archived workspace safely, and would race daemon creation and archival. Older daemons have no key-to-workspace primitive to invoke. Keeping the mapping in Paseo preserves the existing ownership boundary, while the optional acknowledgement gives Hub a forward-progressive capability negotiation.

Goals

  • Accept an optional Hub workspace-affinity lease without changing ordinary agent creation.
  • Ignore additive fields from newer Hubs inside the optional lease.
  • Persist only a SHA-256 affinity ID, never the raw custom key.
  • Serialize creation per affinity key so concurrent first arrivals bind one workspace.
  • Reuse active workspaces and restore archived workspaces after restart.
  • Extend retention to the latest matching workflow max_runtime deadline.
  • Archive affinity agents independently, then archive the workspace at the retained deadline when safe.
  • Keep acknowledged cleanup daemon-owned across relationship retirement and daemon restart.
  • Repair crash-interrupted provisional mappings before acknowledging an idempotent replay.
  • Retry archival after transient errors or while an unrelated live agent protects the workspace.
  • Hold a workspace archive exclusion from the ownership check through teardown and worktree removal.
  • Report backing-directory cleanup failures independently of workspace IDs, including worktree-scope retries after every workspace record is already archived.
  • Hold a workspace-scoped registration lease from create-command entry through asynchronous provider resolution and final agent registration; top-level creates without a workspace yet use a daemon-wide provisioning lease so archive cannot race identity creation.
  • Begin handle-based resumes under an unresolved registration lease before looking up persisted workspace identity, then nest the matched workspace lease across unarchive and provider startup.
  • Treat same-workspace MCP descendants of an affinity-owned root as part of its expiry cleanup, including when the root record is already archived; detached agents and unrelated roots remain blockers.
  • Drain detach and parent-label mutations that began before workspace archival classifies agents, and reject new relationship mutations once the archive exclusion owns the workspace.
  • Register stored-only detach and reparent mutations before their asynchronous workspace lookup, so archival cannot overtake the unresolved lookup.
  • Hold terminal creation leases across legacy workspace lookup and at the shared terminal-manager boundary, so session RPC, MCP, bootstrap, scripts, and future callers cannot create a terminal after archival has enumerated workspace terminals.
  • Register snapshot unarchive before its asynchronous registry lookup, then nest the effective workspace lease through native restore and durable activation so affinity blocker classification cannot race an archived-to-active transition.
  • Hold a workspace-scoped registration lease from affinity restoration through matching agent creation, so ordinary archival cannot overtake the gap between restoring the workspace and registering its next agent.
  • Register storage-backed agent loading under an unresolved activation lease before record lookup, then nest the stored workspace lease through provider startup, agent registration, and history hydration.
  • Acquire a requested workspace lease before provider-import lookup, or an unresolved lease before provisioning a new import workspace, and retain the resolved workspace lease through provider registration.
  • Resolve workspace-ID archive targets only after acquiring the workspace exclusion, and run every workspace recovery plan under the matching activation lease so expiry and manual restore serialize in either order.
  • Begin open_project_request under an unresolved activation lease before its first filesystem or registry lookup, covering exact-path archived workspace reuse through durable activation and response publication.
  • Begin standalone workspace.create.request and MCP create_workspace provisioning under an unresolved lease before source lookup, so expiry cannot remove an affinity-owned backing worktree before the sibling workspace is durable.
  • Hold scheduled new-agent provisioning under the unresolved registration lease through the first durable agent registration, so expiry cannot remove its backing worktree during the provisioning gap.
  • Hold a workspace-scoped lease across MCP workspace rename lookup and persistence, so a concurrent expiry cannot be overwritten by a stale active record.
  • Validate a pending duplicate execution's affinity ID and full target before sharing work, and serialize matching retries through durable replay so a later retention deadline is still extended without a second provider session.
  • Recover provisional mappings from persisted affinity-owned agents during awaited daemon startup before arming retention timers.
  • Acknowledge affinity only when the persisted execution owner actually has the affinity binding.
  • Document Hub configuration and progressive compatibility.

Non-goals

  • Requiring a coordinated daemon rollout.
  • Inferring affinity when a workflow does not opt in.
  • Sharing one agent or serializing all matching executions.
  • Treating idle_timeout as workspace inactivity.
  • Allowing one key to change daemon target, cwd, worktree target, or auto-archive policy.
  • Moving daemon workspace IDs or local lifecycle authority into Hub.

QA

September 7 follow-up: 0a1fbb4af1587a35fb654a6eff72e52619a8bb73 changes only the public affinity guide. The complete Linear trigger example compiles against the updated Hub compiler; the repository formatter check passes. No daemon/runtime code or dependencies changed. The all-workspace typecheck hook was excluded for this documentation-only commit; existing daemon evidence below is from the implementation commits. The current-main merge conflict is unchanged and is not resolved by the docs update.

Behavior verified locally on Linux:

  • pre-commit formatting, lint, and all workspace typechecks passed
  • protocol Hub message suite: 33 tests passed
  • workspace-affinity manager suite: 4 tests passed
  • daemon-execution lifecycle suite: 16 tests passed
  • focused daemon bootstrap start/stop smoke test passed
  • workspace archive, agent-manager, and affinity race suites: 195 tests passed
  • added regressions for additive future lease fields, cleanup after relationship disconnect and restart, and crash-interrupted provisional mapping repair before acknowledgement
  • added regressions proving opaque affinity key whitespace is preserved while blank-only keys remain invalid
  • added regressions proving in-flight registrations drain or fail closed and unrelated agents are checked inside the archive exclusion
  • added regressions proving partial agent, terminal, teardown-command, record, and disk cleanup failures remain retryable
  • added a typed incomplete-archive failure at the shared boundary so session RPC, CLI/worktree, MCP, scheduler, auto-archive, and ordinary Hub callers cannot report partial cleanup as success; affinity expiry explicitly consumes the structured result so it can retry
  • workspace archive and affinity suites: 25 tests passed after the final failure-propagation change; all three session archive RPC regressions passed, including the partial-teardown error response
  • retained the regression proving a legacy pre-affinity execution cannot produce a false workspaceAffinityApplied acknowledgement
  • retained timer coverage for archive exceptions and unrelated live-agent protection
  • create, agent-manager, workspace-archive, and affinity suites: 206 tests passed after adding the pre-registration create/archive race regression
  • create, agent-manager, workspace-archive, and affinity suites: 209 tests passed after coordinating top-level MCP creation before its workspace identity exists
  • affinity-manager and workspace-archive boundary suites: 27 tests passed after adding recursive descendant classification and an archived-root ancestry regression
  • relationship/archive concurrency regressions: 2 focused tests passed, including an in-flight detach held across persistence and detach/reparent attempts after fencing; the 27 affinity/archive boundary tests also passed
  • provisional-mapping startup regression: 28 affinity/archive boundary tests and all 21 daemon bootstrap smoke tests passed, including recovery and expiry without any Hub replay
  • persisted-resume/archive regressions: provider-session lookup starts under the unresolved lease, persisted unarchive and provider resume both run under the nested workspace lease, and the workspace exclusion drains an in-flight resume before teardown; all 8 focused tests passed
  • complete affected session-workspace and agent-manager suites: 283 tests passed and 4 skipped when rerun outside the filesystem sandbox required by their Git subprocess fixtures
  • final terminal/archive boundary regressions: 11 focused archive-exclusion tests and all 12 terminal-controller tests passed, covering scoped creation, legacy unresolved-to-scoped lookup, and archival rejection/draining
  • final stored-only relationship lookup regressions: detach and reparent both register before lookup and complete before archival observes labels; the complete affected session-workspace and agent-manager suites now pass 287 tests with 4 skipped outside the filesystem sandbox
  • final affinity and workspace-archive suites: 28 tests passed, including the host-permission rerun required by temporary Git fixtures
  • final shared terminal-manager boundary regressions: the in-process and worker managers both retain the workspace lease through terminal registration/worker acknowledgement, and all 84 terminal-manager, worker-manager, and daemon-bootstrap tests passed
  • final unarchive/archive boundary regressions: an in-flight snapshot restore drains before blocker classification and a restore beginning after classification is rejected; all 209 agent-manager, workspace-archive, and affinity tests passed, and the complete affected session-workspace/agent-manager suites passed 289 tests with 4 skipped outside the filesystem sandbox
  • final affinity restore/create boundary regression: the workspace registration lease is active during both restoration and matching agent creation, and an ordinary archive exclusion waits until creation completes; all 7 affinity-manager tests, all 16 daemon-execution tests, and all 21 daemon bootstrap smoke tests passed
  • final stored-agent loading/archive regression: archival waits while both the record lookup and provider resume are paused; all 190 agent-loading/agent-manager/affinity tests, all 22 workspace-archive tests, and all 61 schedule service/session tests passed
  • final provider-import/archive regressions: an import that starts first retains its requested workspace lease across lookup and provider registration, while an import that starts after archival owns the workspace is rejected before lookup; all 220 import, agent-manager, and workspace-archive tests passed outside the filesystem sandbox
  • final workspace-recovery/expiry regressions: recovery that starts first drains before archive target resolution, archival that starts first rejects recovery, and workspace state resolution runs inside the exclusion; all 325 affected recovery/archive/session-workspace/affinity/agent-manager tests passed with 4 skipped
  • final open-project/expiry regression: an open request that starts first holds the unresolved activation lease before directory lookup and drains through archived workspace activation, while an archive that starts first rejects the request before lookup; all 326 affected tests passed with 4 skipped
  • final standalone-provisioning, rename, and duplicate-create regressions: session and MCP workspace creation serialize with expiry in both orderings, an in-flight rename cannot resurrect an archived workspace, conflicting concurrent affinity keys/targets fail before sharing, and a matching retry extends retention without a second provider session; the complete affected Hub/session/MCP files passed 246 tests with 4 skipped
  • final scheduled-provisioning and late-terminal-worker regressions: scheduled new-agent creation now serializes with expiry from pre-provisioning through registration, and an uninterruptible worker terminal create retains its workspace lease past the ordinary request timeout until response or worker exit; all 327 affected schedule, terminal-manager, agent-manager, and workspace-archive tests passed outside the filesystem sandbox
  • final residual-worktree cleanup regression: a repeated worktree-scope deletion failure remains a typed incomplete archive after the first attempt archived the last workspace record; all 65 affected archive, affinity, bootstrap, and auto-archive tests passed, plus full formatting, lint, and all-workspace typechecks
  • final pre-commit formatting, lint, and all-workspace typechecks passed

No UI changed, so screenshots and recordings are not applicable. macOS, Windows, iOS, and Android were not tested because the change is isolated to protocol and server behavior.

Companion cross-repository integration runs in getpaseo/hub#86 against exact commit bb3a46346c7e781bc963ffb2e0fdbd3f5ed3efa3.

Checklist

  • One focused change
  • npm run typecheck passes
  • npm run lint passes
  • npm run format passes
  • QA evidence
  • Tests added or updated where it made sense

@michaelmwu

Copy link
Copy Markdown
Contributor Author

Companion Hub PR: getpaseo/hub#86

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

ℹ️ 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/server/src/server/hub/execution-controller.ts Outdated
Comment thread packages/server/src/server/hub/workspace-affinity.ts

@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

const existing = await this.agentStorage.findByDaemonExecution(owner);
if (existing) {
requireExecutionWorkspaceId(existing);
this.requireAuthority(authorityGeneration);
return this.resolveRecord(existing);

P2 Badge Repair provisional mappings before replay acknowledgement

If the daemon exits after the affinity-owned agent record is durably written but before WorkspaceAffinityManager.create() persists the resulting workspaceId, restart loads a provisional mapping with no timer. This early replay return bypasses resolvePlacement, so the mapping is not repaired or armed even though the response acknowledges affinity; without a later archive control, the workspace misses retainUntil. Fresh evidence beyond the earlier pre-affinity replay case is this interrupted first-create state, which already has an affinity owner but an incomplete mapping.

ℹ️ 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/protocol/src/messages.ts Outdated
Comment thread packages/server/src/server/hub/daemon-executions.ts Outdated
@michaelmwu

Copy link
Copy Markdown
Contributor Author

Addressed the remaining provisional-mapping review in 41af71382. An idempotent replay whose stored owner already carries the affinity hash now validates the requested key/target, repairs or recreates the durable key-to-workspace mapping, re-arms retention, and restores the workspace before returning workspaceAffinityApplied: true. A crash-state regression clears the persisted placement, reconstructs execution state, and verifies both the same agent identity and the repaired mapping before acknowledgement.

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

ℹ️ 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/server/src/server/hub/workspace-affinity.ts Outdated
@michaelmwu

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bbc9a8cbfa

ℹ️ 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/server/src/server/bootstrap.ts
@michaelmwu

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c5070b9562

ℹ️ 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/protocol/src/messages.ts Outdated
@michaelmwu

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e396105e31

ℹ️ 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/server/src/server/workspace-archive-service.ts
@michaelmwu

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2b8c23fddf

ℹ️ 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/server/src/server/agent/agent-manager.ts
@michaelmwu

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5d0cec4bb5

ℹ️ 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/server/src/server/agent/create-agent/create.ts
@michaelmwu

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3ac535722a

ℹ️ 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/server/src/server/hub/workspace-affinity.ts Outdated
@michaelmwu

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3997c3593d

ℹ️ 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/server/src/server/agent/agent-manager.ts
@michaelmwu

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 65d4b4c2e3

ℹ️ 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/server/src/server/agent/agent-manager.ts
@michaelmwu

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0b164ec113

ℹ️ 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/server/src/server/workspace-archive-service.ts
@michaelmwu

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0b36a20364

ℹ️ 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/server/src/server/session.ts
@michaelmwu

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4ad9affd87

ℹ️ 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/server/src/server/workspace-archive-service.ts
Comment thread packages/server/src/server/hub/workspace-affinity.ts
Comment thread packages/server/src/server/hub/daemon-executions.ts Outdated
@michaelmwu

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fb642e8a5b

ℹ️ 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/server/src/server/schedule/service.ts
Comment thread packages/server/src/terminal/worker-terminal-manager.ts
@michaelmwu

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ee37f98b62

ℹ️ 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/server/src/server/workspace-archive-service.ts
@michaelmwu

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

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

Reviewed commit: ef9202c3d2

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

…260829

# Conflicts:
#	packages/server/src/server/bootstrap.ts
@greptile-apps

greptile-apps Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds progressive Hub workspace affinity, including protocol negotiation, durable key-to-workspace bindings, restart recovery, retention-driven archival, and archive-exclusion leases across agent, terminal, recovery, import, scheduling, and relationship paths.

  • Adds optional affinity request and acknowledgement fields while preserving compatibility with older Hub and daemon versions.
  • Introduces durable affinity mapping, exact workspace reuse/restoration, deadline extension, startup repair, and retryable cleanup.
  • Coordinates workspace archival with agent registration, terminal creation, relationship mutation, provisioning, and recovery operations.
  • Expands protocol, lifecycle, race, restart, and partial-cleanup coverage and documents Hub configuration.

Confidence Score: 4/5

The PR appears safe to merge, with a non-blocking test-maintainability issue around timing-dependent concurrency assertions.

The reviewed production paths consistently validate affinity ownership and targets, persist and recover mappings, extend retention serially, and coordinate archival with resource creation; the only accepted concern is that several new race tests infer blocked progress from event-loop timing rather than explicit synchronization.

Files Needing Attention: packages/server/src/server/agent/agent-loading.test.ts and packages/server/src/server/agent/agent-manager.test.ts

Important Files Changed

Filename Overview
packages/server/src/server/hub/workspace-affinity.ts Adds the durable affinity state machine, serialized binding, recovery, timer management, restoration, and retryable expiry cleanup.
packages/server/src/server/hub/daemon-executions.ts Integrates affinity validation and acknowledgement with execution creation, duplicate replay, ownership, and archive control.
packages/server/src/server/agent/agent-manager.ts Adds workspace-scoped and unresolved leases that serialize registration, terminal creation, relationship mutation, activation, and archival.
packages/server/src/server/workspace-archive-service.ts Strengthens archive exclusion and structured partial-failure reporting for retryable workspace and backing-directory cleanup.
packages/protocol/src/messages.ts Adds backward-compatible optional affinity lease and acknowledgement fields with boundary validation.
packages/server/src/server/agent/agent-loading.test.ts Adds stored-agent loading/archive race coverage, but uses inline event-loop waits instead of explicit synchronization helpers.
packages/server/src/server/agent/agent-manager.test.ts Adds broad lease and archive-exclusion regression coverage, with several repeated timing-dependent test assertions.
docs/hub.md Documents affinity reuse, retention, progressive capability negotiation, archival behavior, and restart ownership.

Sequence Diagram

sequenceDiagram
  participant Hub
  participant Exec as DaemonExecutions
  participant Affinity as WorkspaceAffinityManager
  participant Workspace
  participant Agent
  participant Archive as WorkspaceArchiveService

  Hub->>Exec: create(executionId, affinity key, deadline)
  Exec->>Affinity: hash and bind affinity
  Affinity->>Affinity: persist provisional mapping
  Affinity->>Workspace: reuse active or restore archived workspace
  Affinity->>Agent: create affinity-owned agent under registration lease
  Agent-->>Affinity: workspaceId and cwd
  Affinity->>Affinity: persist placement and arm deadline
  Exec-->>Hub: agent + workspaceAffinityApplied

  Hub->>Exec: matching later execution
  Exec->>Affinity: validate target and extend retention
  Affinity->>Workspace: reuse exact workspace
  Affinity->>Agent: create separate agent
  Exec-->>Hub: affinity acknowledged

  Affinity->>Archive: archive at retained deadline
  Archive->>Agent: classify and archive affinity ancestry
  Archive->>Workspace: archive workspace when no unrelated blockers
  Archive-->>Affinity: success, blocked, or retryable failure
Loading

Reviews (1): Last reviewed commit: "Document trigger affinity and Linear iss..." | Re-trigger Greptile

Comment on lines +161 to +167
await new Promise((resolve) => setImmediate(resolve));
expect(archiveStarted).toBe(false);

finishLookup.resolve();
await resumeStarted.promise;
await new Promise((resolve) => setImmediate(resolve));
expect(archiveStarted).toBe(false);

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.

P2 Timing-dependent archive race assertions

These concurrency tests use setImmediate and mutable booleans to infer that archival remains blocked. This depends on incidental event-loop progress and repeats across the new loading, detach, and reparent tests; use an explicit reusable synchronization signal so the regressions remain deterministic and clearly express the lifecycle boundary.

Rule Used: # Code Review Pattern Reference: Slop, Tests, Feat... (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@boudra

boudra commented Sep 8, 2026

Copy link
Copy Markdown
Collaborator

Closing in favor of the implementation merged in #4354.

@boudra boudra closed this Sep 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants