Skip to content

🤖 tests: record the options of each session lock call - #7290

Merged
ThomasK33 merged 16 commits into
mainfrom
phase4/call-record
Oct 23, 2026
Merged

ThomasK33 merged 16 commits into
mainfrom
phase4/call-record

Conversation

@ThomasK33

@ThomasK33 ThomasK33 commented Oct 23, 2026 •

Copy link
Copy Markdown
Member

Summary

Adds a test that records each session lock call that a few real scenarios make: the source file of the call, the lock function and all its arguments (every option). A fixture pins today's calls. It is PR 2 of phase 4 (session locks behind one SessionLocks service). Each later move PR must keep this fixture byte for byte, so a move that changes a lock path, a timeout, a label or any other option fails.

Background

Phase 4 moves the lock calls of 27 files behind SessionLocks, with no change of behavior. The moved calls keep their options by hand. A changed timeout or path changes behavior only under contention, which normal tests do not reach. This record makes such a change visible in review. This PR covers the 9 files of the first group (history, agent session, turn manager, removal, branch summary, refine, durable journal, todo and review pane tools). PR 3 adds the other 18 files.

Implementation

  • sessionLocks.callOptions.test.ts spies on the lock modules: the fileLock and crossProcessLock namespaces, WorkspaceUseLeases.prototype.hold and the shared workspaceFileLocks.withLock. In Bun, a spy on a module namespace also reaches the named imports of the callers, so the record sees each call before and after a move. callSite() takes the first source file on the stack and skips the SessionLocks layers, which only forward a call. Calls from test files are left out.
  • sessionLocks.callOptions.scenarios.testHarness.ts runs the scenarios through public entry points: one turn, one refusal of a mutation in a turn, one removal, one refine apply and one fork.
  • Each row records every argument of the call, serialized by kind: strings are masked, functions and AbortSignals become fixed tokens, and any other kind fails the test with an assertion. So no option can drop out of the record (createParentDirectory, for example). This replaced a chosen list of keys in review round 4, because rounds 1, 2 and 4 each found one more key that the list left out.
  • The workspaceFiles.withLock key and the WorkspaceUseLeases.hold workspace id are arguments, so the record has them too. A move that passes the wrong id fails.
  • callSite() reads the stack-frame path up to .ts:line:col, so a checkout path with spaces (or a drive letter) still parses.
  • Paths are masked by name, not by order of use. Each scenario names the temp roots and workspace ids it creates (<root:turn>, ws-record-turn), and the removal names its memory target keys. The test turns each name into digests with the code's own path functions (historyWriteLockPath, refineApplyLockPath, workspaceMutationLockPath, workspaceUseLockDir, targetMutationLockFilePath), so a digest shows as <hash:history:ws-record-turn>. Each digest scheme has its own name: history (SHA-256 of UTF-8, cut to 32 characters: the history and refine-apply locks), workspace-use (SHA-256 of UTF-16LE: the mutation gate and the use leases) and target (memory target keys). The test checks that the paths of one scheme share one digest, and that a digest keeps one name. So a lock built with the other scheme's digest shows the other name (review round 5). A digest or temp path with no name fails the test with a clear message (lock calls with no name: ...). So a lock built from the wrong id or root fails even when it occurs once. This replaced first-use numbering in review round 4, because rounds 2, 3 and 4 each found one more case that the numbering hid. Uuids (lease tokens) are masked. Rows are sorted and deduplicated, so the fixture is stable.
  • The scenarios build their HistoryService with createTestHistoryService().
  • The rows are sorted, so they cannot show lock order. One explicit check keeps the order of removal: refine, then target, then history. Another order can deadlock against an apply that holds refine and waits for history.
  • Record again after an intended change: UPDATE_FIXTURE=1 bun test ./src/node/services/sessionLocks/sessionLocks.callOptions.test.ts, then make fmt.

Validation

  • Tripwire (loopTestBaseline.ts --runs 3 --base origin/main) on the round-5 head: 0 trips. The round-5 fix changes only names in the test file and the fixture, and the phase lead counts this tripwire for the final head.
  • bun test ./src/node/services/sessionLocks/sessionLocks.callOptions.test.ts: passes, about 1 s, and 10 more runs passed, also 3 repeats in one process.
  • Scratch edit: the withLock key in tools/todo.ts changed -> the test fails with a diff on that row's key. Reverted.
  • Scratch edit: AgentSession holds the turn lease for a wrong workspace id -> the test fails on the hold row and on the history lock token. Reverted.
  • Scratch edit: historyService.ts builds the history write lock from ${workspaceId}-other -> the test fails with lock calls with no name: <the three new digests>. Reverted.
  • Scratch edit: historyService.ts builds the history write lock path from the workspaceUseLockDir digest (the UTF-16LE scheme) -> the test fails with a diff from history-<hash:history:...> to history-<hash:workspace-use:...> on each history row. Reverted.
  • Scratch edit: workspaceUseLeases.ts passes createParentDirectory: false to the turn lease's acquireCrossProcessLock -> the test fails with a diff that adds "createParentDirectory": false to both lease rows. Reverted. (No call in the scenarios passes false today, only WorkflowRunStore, so the scratch edit adds the option where the review finding said a move could add it. At the turn owner lock in workspaceTurnManager.ts the same edit makes the scenario itself fail before the record compare, because that lock directory does not exist yet.)
  • Scratch edit: the 10 000 ms timeout of the removal lock in workspaceRemoval.ts changed -> the test fails with a diff on that row. Reverted.
  • make test and its second half (tests/ui/storybook/, tests/ui/domIsolation.test.ts, vscode/src/, scripts/) on the 🤖 tests: record the session lock calls of 18 more files #7291 head 069b820 (which contains this PR) pass except WorkspaceMenuBar.test.tsx and scripts/perf/pageTimingCore.test.ts, known failures on this older base (fixed on main by 🤖 tests: make test-unit runs CI's isolated files alone and ends a leaked metadata loop #7305), and the known load flake backgroundProcessManager.test.ts, which passed alone (163 of 163).
  • Mutation run (scripts/mutate/check.ts, base = this PR's base): PASS with 0 mutants. The PR changes only test files, so no survivor needs a disposition.

Known limits of the record

  1. The rows are sorted, so they show no lock order except the removal order that the test checks. The record cannot see if WorkspaceUseLeases.hold() inspects the mutation gate before it acquires the use-lease file. Phase 4 PR 4 adds an explicit order check for that (review round 6).
  2. The digest names come from the production hash builders. A move that changes a hash scheme changes the path and its name together, so the fixture still matches. Phase 4 PR 4 pins fixed digests for the fixed test IDs and keys, before PRs 9, 12 and 13 touch the files of those builders (review round 6).

Deferred review findings

#7326 tracks the findings that this PR declined, each with the PR that must close it: the two limits above, seeding HistoryService in beforeEach (round 4) and Windows path separators (round 2).

Risks

Test-only. The record depends on stack traces: if a refactor changes which source file makes a call, the site of a row changes although the options do not. The PR that does so records the fixture again and explains the row change.


Generated with xum • Model: anthropic:claude-opus-5-5 • Thinking: high • Cost: $70.87

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 23, 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-23T09:44:17.281865Z 7841035 New commits
🔒 Security Review ✅ Completed 2026-10-23T10:47:04.113452Z 7841035 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.

@ThomasK33
ThomasK33 added this pull request to stack #7292 October 23, 2026 03:04

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

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/node/services/sessionLocks/sessionLocks.callOptions.test.ts
Comment thread src/node/services/sessionLocks/sessionLocks.callOptions.test.ts
@github-actions

github-actions Bot commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

🟢 e2e stories (Haiku): 14 passed

27 agent steps · 7 replayed from cache · 36 model calls · 278.9k tokens (79% cached)
Spend: $0.09 of the $1.00 cap (proxy ledger)

All 14 tests in 9 files
Test Agent Time
🟢 chatRestart.e2e.ts · 1 passed 2 steps · 5 calls 26.6s
🟢 a chat survives a restart of the server 2 steps · 5 calls 26.6s
🟢 compaction.e2e.ts · 1 passed 3 steps · 10 calls 49.8s
🟢 /compact replaces the old chat with a summary 3 steps · 10 calls 49.8s
🟢 pluginTrustRestart.e2e.ts · 1 passed 4 steps · 2 calls 9.1s
🟢 a trusted plugin hook stays trusted after the server restarts 4 steps · 2 calls 9.1s
🟢 settingsRoundTrip.e2e.ts · 1 passed 3 steps · 5 calls 34.0s
🟢 a chat survives trips through Settings 3 steps · 5 calls 34.0s
🟢 sidebarPerWorkspace.e2e.ts · 1 passed 4 steps · 1 call 4.6s
🟢 a new workspace starts with its right sidebar collapsed while another keeps it open 4 steps · 1 call 4.6s
🟢 smoke.e2e.ts · 1 passed 2 steps · 1 call 2.7s
🟢 the agent opens the playground workspace 2 steps · 1 call 2.7s
🟢 streamErrors.e2e.ts · 1 passed 1 step · 1 call 6.9s
🟢 stream errors show in the chat, and the chat recovers 1 step · 1 call 6.9s
🟢 todoNudge.e2e.ts · 1 passed 2 steps · 5 calls 27.4s
🟢 the agent finishes open TODO items after the turn-end nudge 2 steps · 5 calls 27.4s
🟢 touchAlignment.e2e.ts · 6 passed 6 steps · 6 calls 25.1s
🟢 the Settings close button is level with the title on a touch screen 390px wide 1 step · 1 call 4.5s
🟢 the Settings close button is level with the title on a touch screen 768px wide 1 step · 1 call 4.4s
🟢 Backup settings checkboxes are small and level with their labels on a touch phone 1 step · 1 call 5.6s
🟢 the heartbeat checkbox is small and level with its label on a touch phone 1 step · 1 call 3.4s
🟢 a reply's model and time stay on one line on a touch phone 1 step · 1 call 4.3s
🟢 the workspace actions menu stays on the title row on a touch phone 1 step · 1 call 3.0s

e2e 0.20.0 · 3m 9s · web · run artifacts

🟢 e2e Electron stories (Haiku): 3 passed

3 agent steps · 3 model calls · 8.1k tokens (32% cached)
Spend: $0.01 of the $1.00 cap (proxy ledger)

All 3 tests in 3 files
Test Agent Time
🟢 electron/deepLink.e2e.ts · 1 passed 1 step · 1 call 5.4s
🟢 a deep link of a second launch starts a chat in the running app 1 step · 1 call 5.4s
🟢 electron/menuBar.e2e.ts · 1 passed 1 step · 1 call 5.7s
🟢 the workspace menu bar is the desktop title bar 1 step · 1 call 5.7s
🟢 electron/smoke.e2e.ts · 1 passed 1 step · 1 call 6.5s
🟢 Xum Electron opens the playground workspace 1 step · 1 call 6.5s

e2e 0.20.0 · 19.7s · electron · run artifacts

🟢 e2e agent repros (Haiku): no tests selected

Spend: $0.00 of the $1.00 cap (proxy ledger)

e2e 0.20.0 · 5.3s · 2 targets (web, phone) · run artifacts

Base automatically changed from phase4/kill-test to main October 23, 2026 04:09

@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: 2b0817b6e9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/node/services/sessionLocks/sessionLocks.callOptions.test.ts Outdated
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

…call-record

# Conflicts:
#	src/node/services/sessionLocks/__fixtures__/callOptions.json
#	src/node/services/sessionLocks/sessionLocks.callOptions.test.ts
@ThomasK33

Copy link
Copy Markdown
Member 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: 9650c17be4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/node/services/sessionLocks/sessionLocks.callOptions.test.ts Outdated
Comment thread src/node/services/sessionLocks/sessionLocks.callOptions.test.ts
Comment thread src/node/services/sessionLocks/sessionLocks.callOptions.scenarios.testHarness.ts Outdated
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review · Automatically triggered

Security review completed. No security issues were found in this pull request.

Reviewed commit: 480bb5a516

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

@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: 480bb5a516

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/node/services/sessionLocks/sessionLocks.callOptions.test.ts Outdated
Comment thread src/node/services/sessionLocks/sessionLocks.callOptions.test.ts Outdated
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review · Automatically triggered

Security review completed. No security issues were found in this pull request.

Reviewed commit: 5ed6316f5b

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

@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: 5ed6316f5b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/node/services/sessionLocks/sessionLocks.callOptions.test.ts Outdated
Comment thread src/node/services/sessionLocks/sessionLocks.callOptions.test.ts Outdated
@ThomasK33

Copy link
Copy Markdown
Member Author

Review loop paused at round 4 (non-convergence rule in AGENTS.md). I fixed nothing in this round.

The round-4 findings repeat two areas of earlier rounds:

  1. Identity lost by masking: lock hashes (round 2), temp roots (round 3), and now single-use digests (PRRT_kwDOPxxmWM6vgtmJ). First-use numbering cannot keep the identity of a value that occurs once.
  2. Fields that the record leaves out: the withLock key (round 1), the hold workspace ID (round 2), and now createParentDirectory of acquireCrossProcessLock (PRRT_kwDOPxxmWM6vgtmR).

Each fix closed one case, and the next round found the next case of the same kind. So the design of the record is the problem, not one more field or token. The phase lead decides the next step with the maintainer. The third finding (PRRT_kwDOPxxmWM6vgtmT, seeding HistoryService in beforeEach) is test hygiene, not a gap in the record. I will answer it when the loop continues.

The three threads stay open until then.

@ThomasK33

Copy link
Copy Markdown
Member Author

The review loop continues, with a design change of the record (approved by the phase lead).

Rounds 1 to 4 kept finding new cases in two areas: a key that the record left out, and an identity that the first-use numbering hid. The change removes both hand-made parts instead of adding one more key or token:

  1. Each row now keeps every argument of the lock call, serialized by kind. An argument of an unknown kind fails the test. No option can drop out.
  2. Roots and digests are masked by name. The scenarios name their temp roots and workspace ids, and the test makes the digests with the code's own path functions. A digest or temp path with no name fails the test.

Scratch edits that fail now: the history lock built from a wrong workspace id, and createParentDirectory: false added at the turn lease. Details are in the PR description. The change is test-only.

@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review · Automatically triggered

Security review completed. No security issues were found in this pull request.

Reviewed commit: 71bebea2c1

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

@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: 71bebea2c1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/node/services/sessionLocks/sessionLocks.callOptions.test.ts Outdated
@ThomasK33

Copy link
Copy Markdown
Member Author

Review loop paused at round 5. I fixed nothing in this round.

The round-5 finding (PRRT_kwDOPxxmWM6vh7aX) is valid and is again in the identity-masking area: the name map gives the 32-character UTF-8 digest (history and refine-apply locks) and the 64-character UTF-16LE digest (mutation gate and use leases) the same name, <hash:<id>>. So a history lock built with the use-lease digest would still match the fixture. The phase lead set a stop rule for round 5 when either class came back. The lead now decides the scope with the maintainer. The thread stays open until then.

@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: 7841035d0d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/node/services/sessionLocks/sessionLocks.callOptions.test.ts
Comment thread src/node/services/sessionLocks/sessionLocks.callOptions.test.ts
@ThomasK33

Copy link
Copy Markdown
Member Author

Review loop stopped at round 6, the last round under the cap. I fixed nothing in this round.

Round 6 brought two new findings on 7841035: PRRT_kwDOPxxmWM6vjS7Z (the record sorts away the acquire-before-inspect order of WorkspaceUseLeases.hold()) and PRRT_kwDOPxxmWM6vjS7d (the digest names come from the production path functions, so a changed hash scheme moves both sides). Both are in the areas of earlier rounds (lock order, and identity masking). The phase lead and the maintainer decide the next step. The threads stay open until then.

@ThomasK33

Copy link
Copy Markdown
Member Author

@codex security review

@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review

Security review completed. No security issues were found in this pull request.

Reviewed commit: 7841035d0d

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

@ThomasK33
ThomasK33 added this pull request to the merge queue Oct 23, 2026
Merged via the queue into main with commit fefaf77 Oct 23, 2026
70 of 74 checks passed
@ThomasK33
ThomasK33 deleted the phase4/call-record branch October 23, 2026 11:05
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.

1 participant