Hacktoberfest 2026:メンテナが10月に向けて印を付けた、オープンで初心者向けの issue。 Hacktoberfest の issue を見る

Replace the driver install lock primitive: directory-rename cannot make claim-and-verify atomic, and the inode guard is not portable

オープン
#1,206 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

まだ誰も着手していません。

評価

難易度
5/5
見積もり時間
1週間以上
初心者へのやさしさ
35/100
issue の種類
リファクタリング
明瞭さ
明確に書かれている
活発さ
活発
技術スタック
typescript
領域
tooling

調査の方向性

packages/drivers/src/resolve.ts の withInstallLock、claimStaleLock、isStaleLock、releaseInstallLock、installLockPath、heldLockPath から始め、次に packages/drivers/test/install-lock.test.ts と #1201 に関連する動作を読みます。提案されている O_EXCL sentinel の方針を使用し、マルチプロセスの制御を含めます。完了とは、テストが取得、古い lock の claim、identity-safe な解放、および特定された contention の欠落を、inode の比較に依存せずにカバーしていることを意味します。

索引モデルが issue の本文から書いたものです。

説明

Summary

The cross-process driver install lock added in #1201 uses a lock directory plus rename as its primitive, with an inode comparison covering one window the ownership token cannot. Three independent reviewers, across three review rounds, converged on the same structural conclusion: that primitive cannot make "confirm this is still the lock I judged stale" and "claim it" a single atomic step, and the inode fallback rests on a guarantee that is not portable.

This issue tracks replacing the primitive. It is deliberately not a bug report against #1201 — that PR is a large net improvement over main, where there is no cross-process lock at all — but it should not be mistaken for a proof of mutual exclusion, and the remaining gaps should not be patched further in place.

Why replace rather than repair

Three rounds of fixes on this protocol each closed real races and then exposed new ones in the compensating branches themselves:

  • Round 1 added the lock. Review found stale cleanup could delete a peer's fresh lock.
  • Round 2 made the claim a rename (atomic, one winner) and added a pre-check plus a post-rename verify-and-restore. Review found the restore branch leaves the lock pathname free, so a third contender can take it, the restore fails, and the moved live lock is deleted — admitting two owners.
  • Round 2 also added an inode check for the mkdir → owner.json window the token cannot cover. Review found st_ino is not a portable identity.

That pattern — each compensating branch generating the next finding — is the signature of a protocol being asked for a guarantee it cannot give, rather than of a fixable bug.

The specific gaps

1. Claim is not atomic with the staleness verdict. Nothing makes "read the owner record" and "rename the directory" one operation. The current code narrows the window from both sides (re-read before, verify what was actually moved after, restore on mismatch) but cannot close it.

2. The restore branch opens its own window. Between the mismatched rename and the restore, the lock pathname is unoccupied and a third process can create it. The restore then fails and the moved live lock is deleted.

3. Inode identity is not portable. fs.statSync(lockDir).ino is a per-filesystem identity. On Windows (untested on that PR), on overlay and network filesystems, and where a deleted directory's inode is promptly reused, the comparison can always-match (deleting a successor's live lock) or never-match (leaking our own). The failure is silent either way, and it degrades to exactly the pathname deletion it was added to prevent.

4. The lock wait outlasts only one peer. Each process counts its deadline from its own start, so with three or more simultaneous contenders the third's deadline can expire mid-install and it falls through to an unlocked performInstall over the same tree.

Proposed direction

An O_EXCL sentinel file whose content identifies the acquisition, replacing both the directory rename and the inode check:

  • open(path, "wx") is atomic and fails EEXIST when held — the same portable exclusion the lock directory gives — but the file has content, so the acquisition identity travels with the lock itself.
  • Claiming a stale lock becomes read-identity-then-conditionally-replace against a single object, rather than a verdict about one path followed by a rename of another.
  • Release compares the identity in the file, so no inode comparison is needed and the mkdir → owner.json window disappears: the identity is written by the same atomic operation that takes the lock.

Deriving the lock wait from the number of observed contenders, or re-checking readiness rather than falling through on timeout, should be considered alongside it (gap 4).

This wants its own PR, its own tests — including a multi-process control that demonstrates the assertion bites, as #1201's does — and its own review. It should not be appended to #1201.

Evidence

Six review threads on #1201, from three independent reviewers, all reaching this conclusion:

Reviewer Finding Thread
codex Block new acquisitions while restoring a stale-lock claim https://github.com/AltimateAI/altimate-code/pull/1201#discussion_r3888887305
kilo-code releaseInstallLock's inode check relies on an unverified cross-platform guarantee https://github.com/AltimateAI/altimate-code/pull/1201#discussion_r3888899280
cubic Two acquisitions look identical when a stale lock has no readable owner.json https://github.com/AltimateAI/altimate-code/pull/1201#discussion_r3888905549
cubic Restoration rename can fail; the catch then deletes the moved live lock https://github.com/AltimateAI/altimate-code/pull/1201#discussion_r3888905551
cubic Release safety depends on a platform-dependent, unverified inode premise https://github.com/AltimateAI/altimate-code/pull/1201#discussion_r3888905561
codex Do not use reusable inodes as lock ownership https://github.com/AltimateAI/altimate-code/pull/1201#discussion_r3888928250

Related but separate, also open on #1201 and not covered by this redesign:

Scope

  • withInstallLock, claimStaleLock, isStaleLock, releaseInstallLock, installLockPath / heldLockPath in packages/drivers/src/resolve.ts
  • packages/drivers/test/install-lock.test.ts
  • The external_directory permission patterns in packages/opencode/src/altimate/tools/warehouse-install-driver.ts, if the sentinel changes what paths are written

Relates to #1202.

主要言語
TypeScript
スター
813
フォーク
134
平均マージ
2日 3時間
マージ済み PR(30日)
65

コントリビューションガイド

コントリビューションガイドを開く

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

AltimateAI/altimate-code のほかの issue

AltimateAI/altimate-code の issue をすべて見る

似ている issue

TypeScript の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。