From 3fe844bc70e4ba790736e5710482698222d34920 Mon Sep 17 00:00:00 2001 From: NagyVikt Date: Fri, 15 May 2026 15:45:01 +0200 Subject: [PATCH] Speed up task claim hot path --- apps/mcp-server/src/tools/task.ts | 11 ++---- apps/mcp-server/test/task-threads.test.ts | 21 ++++++++++++ .../.openspec.yaml | 2 ++ .../proposal.md | 23 +++++++++++++ .../specs/speed-up-task-claim-file/spec.md | 22 ++++++++++++ .../tasks.md | 34 +++++++++++++++++++ 6 files changed, 104 insertions(+), 9 deletions(-) create mode 100644 openspec/changes/agent-codex-speed-up-task-claim-file-2026-05-15-15-39/.openspec.yaml create mode 100644 openspec/changes/agent-codex-speed-up-task-claim-file-2026-05-15-15-39/proposal.md create mode 100644 openspec/changes/agent-codex-speed-up-task-claim-file-2026-05-15-15-39/specs/speed-up-task-claim-file/spec.md create mode 100644 openspec/changes/agent-codex-speed-up-task-claim-file-2026-05-15-15-39/tasks.md diff --git a/apps/mcp-server/src/tools/task.ts b/apps/mcp-server/src/tools/task.ts index e13753c..d21134f 100644 --- a/apps/mcp-server/src/tools/task.ts +++ b/apps/mcp-server/src/tools/task.ts @@ -5,7 +5,6 @@ import { classifyClaimAge, guardedClaimFile, listPlans, - liveFileContentionsForClaim, } from '@colony/core'; import { claimPathRejectionMessage } from '@colony/storage'; import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; @@ -396,12 +395,6 @@ export function register(server: McpServer, ctx: ToolContext): void { ); } const previous = store.storage.getClaim(task_id, normalizedFilePath); - const liveContentions = liveFileContentionsForClaim(store, { - task_id, - session_id, - file_path: normalizedFilePath, - assume_requester_live: true, - }); const guarded = guardedClaimFile(store, { task_id, session_id, @@ -453,8 +446,8 @@ export function register(server: McpServer, ctx: ToolContext): void { file_path: normalizedFilePath, claim_status: guarded.status, claim_task_id: guarded.claim_task_id ?? task_id, - warning: liveContentions[0] ?? null, - live_file_contentions: liveContentions, + warning: null, + live_file_contentions: [], overlap: previousClaim?.overlap ?? 'none', previous_claim: previousClaim, }); diff --git a/apps/mcp-server/test/task-threads.test.ts b/apps/mcp-server/test/task-threads.test.ts index 40f1bd7..f4fc943 100644 --- a/apps/mcp-server/test/task-threads.test.ts +++ b/apps/mcp-server/test/task-threads.test.ts @@ -97,6 +97,27 @@ describe('task threads — file claims', () => { expect(claim?.metadata).toContain('"file_path":"src/viewer.tsx"'); }); + it('keeps uncontended task_claim_file calls under the hot-path budget', async () => { + const repoRoot = mkdtempSync(join(dir, 'repo-')); + mkdirSync(join(repoRoot, 'src'), { recursive: true }); + const { task_id, sessionA } = seedTwoSessionTask(repoRoot); + const durations: number[] = []; + + for (let i = 0; i < 40; i += 1) { + const started = performance.now(); + const result = await call<{ live_file_contentions: unknown[] }>('task_claim_file', { + task_id, + session_id: sessionA, + file_path: `src/hot-path-${i}.ts`, + }); + durations.push(performance.now() - started); + expect(result.live_file_contentions).toEqual([]); + } + + const p95 = [...durations].sort((a, b) => a - b)[Math.floor(durations.length * 0.95)] ?? 0; + expect(p95).toBeLessThan(100); + }); + it('rejects pseudo task_claim_file paths with a pseudo-specific message', async () => { const { task_id, sessionA } = seedTwoSessionTask(); diff --git a/openspec/changes/agent-codex-speed-up-task-claim-file-2026-05-15-15-39/.openspec.yaml b/openspec/changes/agent-codex-speed-up-task-claim-file-2026-05-15-15-39/.openspec.yaml new file mode 100644 index 0000000..9f70866 --- /dev/null +++ b/openspec/changes/agent-codex-speed-up-task-claim-file-2026-05-15-15-39/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-05-15 diff --git a/openspec/changes/agent-codex-speed-up-task-claim-file-2026-05-15-15-39/proposal.md b/openspec/changes/agent-codex-speed-up-task-claim-file-2026-05-15-15-39/proposal.md new file mode 100644 index 0000000..510bd24 --- /dev/null +++ b/openspec/changes/agent-codex-speed-up-task-claim-file-2026-05-15-15-39/proposal.md @@ -0,0 +1,23 @@ +## Why + +`task_claim_file` runs on the edit hot path. `colony gain` showed an average +runtime above 3 seconds, and the MCP handler always performed the full live +file contention scan even for ordinary uncontended claims where that payload is +empty. + +## What Changes + +- Remove the unconditional live-contention scan from successful + `task_claim_file` responses. +- Keep the guarded claim decision as the authority for blocking active owners, + stale claims, protected branches, and same-session refreshes. +- Return the existing response shape with `warning: null` and + `live_file_contentions: []` for successful claims. + +## Impact + +- Cuts one repo-wide task/claim scan and OMX active-session read from the common + claim path. +- Preserves existing hard-block behavior for active owners through + `guardedClaimFile`. +- Adds a focused hot-path budget test for uncontended claim batches. diff --git a/openspec/changes/agent-codex-speed-up-task-claim-file-2026-05-15-15-39/specs/speed-up-task-claim-file/spec.md b/openspec/changes/agent-codex-speed-up-task-claim-file-2026-05-15-15-39/specs/speed-up-task-claim-file/spec.md new file mode 100644 index 0000000..7fa2d33 --- /dev/null +++ b/openspec/changes/agent-codex-speed-up-task-claim-file-2026-05-15-15-39/specs/speed-up-task-claim-file/spec.md @@ -0,0 +1,22 @@ +## ADDED Requirements + +### Requirement: task_claim_file avoids live-contention scans on successful claims +The `task_claim_file` MCP handler SHALL avoid the repo-wide live file +contention scan when `guardedClaimFile` returns a successful claim status. For +successful claims it SHALL preserve the response shape with `warning: null` and +`live_file_contentions: []`. The guarded claim decision SHALL remain responsible +for hard failures such as active owners, protected branch rejection, invalid +paths, and takeover recommendations. + +#### Scenario: Uncontended claim returns compact success +- **GIVEN** a task has no competing scoped claim for `file_path=F` +- **WHEN** `task_claim_file` is called for `F` +- **THEN** the claim succeeds +- **AND** the response contains `warning: null` +- **AND** the response contains `live_file_contentions: []` + +#### Scenario: Active owner still blocks +- **GIVEN** another active session owns a scoped claim for `file_path=F` +- **WHEN** `task_claim_file` is called for `F` +- **THEN** the handler returns `CLAIM_HELD_BY_ACTIVE_OWNER` +- **AND** no successful claim is recorded for the requester diff --git a/openspec/changes/agent-codex-speed-up-task-claim-file-2026-05-15-15-39/tasks.md b/openspec/changes/agent-codex-speed-up-task-claim-file-2026-05-15-15-39/tasks.md new file mode 100644 index 0000000..ca6776e --- /dev/null +++ b/openspec/changes/agent-codex-speed-up-task-claim-file-2026-05-15-15-39/tasks.md @@ -0,0 +1,34 @@ +## Definition of Done + +This change is complete only when **all** of the following are true: + +- Every checkbox below is checked. +- The agent branch reaches `MERGED` state on `origin` and the PR URL + state are recorded in the completion handoff. +- If any step blocks (test failure, conflict, ambiguous result), append a `BLOCKED:` line under section 4 explaining the blocker and **STOP**. Do not tick remaining cleanup boxes; do not silently skip the cleanup pipeline. + +## Handoff + +- Handoff: change=`agent-codex-speed-up-task-claim-file-2026-05-15-15-39`; branch=`agent/codex/speed-up-task-claim-file-2026-05-15-15-39`; scope=`skip live-contention scan on successful task_claim_file`; action=`continue this sandbox or finish cleanup after a usage-limit/manual takeover`. +- Copy prompt: Continue `agent-codex-speed-up-task-claim-file-2026-05-15-15-39` on branch `agent/codex/speed-up-task-claim-file-2026-05-15-15-39`. Work inside the existing sandbox, review `openspec/changes/agent-codex-speed-up-task-claim-file-2026-05-15-15-39/tasks.md`, continue from the current state instead of creating a new sandbox, and when the work is done run `gx branch finish --branch agent/codex/speed-up-task-claim-file-2026-05-15-15-39 --base main --via-pr --cleanup`. + +## 1. Specification + +- [x] 1.1 Finalize proposal scope and acceptance criteria for `agent-codex-speed-up-task-claim-file-2026-05-15-15-39`. +- [x] 1.2 Define normative requirements in `specs/speed-up-task-claim-file/spec.md`. + +## 2. Implementation + +- [x] 2.1 Implement scoped behavior changes. +- [x] 2.2 Add/update focused regression coverage. + +## 3. Verification + +- [x] 3.1 Run targeted project verification commands. +- [x] 3.2 Run `openspec validate agent-codex-speed-up-task-claim-file-2026-05-15-15-39 --type change --strict`. +- [x] 3.3 Run `openspec validate --specs`. + +## 4. Cleanup (mandatory; run before claiming completion) + +- [ ] 4.1 Run the cleanup pipeline: `gx branch finish --branch agent// --base dev --via-pr --wait-for-merge --cleanup`. This handles commit -> push -> PR create -> merge wait -> worktree prune in one invocation. +- [ ] 4.2 Record the PR URL and final merge state (`MERGED`) in the completion handoff. +- [ ] 4.3 Confirm the sandbox worktree is gone (`git worktree list` no longer shows the agent path; `git branch -a` shows no surviving local/remote refs for the branch).