feat: multi-instance session lease, write fencing, and fs/watch reliability#1920
Open
7Sageer wants to merge 25 commits into
Open
feat: multi-instance session lease, write fencing, and fs/watch reliability#19207Sageer wants to merge 25 commits into
7Sageer wants to merge 25 commits into
Conversation
🦋 Changeset detectedLatest commit: 725df34 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
commit: |
7Sageer
force-pushed
the
refactor-fs-watch
branch
from
July 19, 2026 14:01
a030953 to
3d7ffc7
Compare
…bility Single-instance reliability: - Journal: preserve content on write failure with sticky JournalStorageError, per-batch fsync, last-header open, and zero-write cold reads - Broadcaster: writeFailure gate, deterministic dispose drain, replay failure now triggers resync_required; graceful close ordering in start.ts - fswatch: per-connection monotonic seq, pinned truncated semantics, and gitignore double-cache invalidation; __global__ session made volatile Cross-process lock unification: - agent-core-v2 CrossProcessLockService: parameterized lock modes (heartbeat-TTL implemented), token-guarded release/update, rename-isolated stale takeover, creation window, PID-reuse detection (conservative on macOS) - config.toml and workspace registry locked read-modify-write; mcp.json watch - kap-server lock protocol aligned (lock_id, process_started_at, three-layer stale detection); minidb release ownership fixed, legacy cleanup removed Multi-instance session ownership (gated by multi_server flag): - Session leases with write fencing; 40921 SESSION_HELD_BY_PEER with typed details (routable/creating/holder-unresponsive/held-by-local-instance) and unregistered-writer detection; write-authority registry hard gate in AppendLogStore, session metadata, and flush paths - kimi-web redirect to the holder with pending approvals/questions replay; klient transparent redirect with loop guard - session.list_changed cross-instance discovery via two-layer fs watch; ownership field on GET /sessions Stale-write fencing and skill hot reload: - Session file ledger + agent file fencing: hard gate with the flag on, advisory note with it off; dirty-tick signals from fs watch - Skill root watcher hot reload: catalog reload, turn-boundary listing reminder, and skill_catalog.changed volatile event to web clients
7Sageer
force-pushed
the
refactor-fs-watch
branch
from
July 19, 2026 14:28
3d7ffc7 to
56f1a5a
Compare
…lock Per-session flock is now held for the entire time a server hosts a session, making the kernel the single arbiter of ownership: process death releases the lock, so heartbeats, TTL-based stale takeover, and pid liveness probing are no longer needed. owner.json is reduced to a redirect hint (instance address), written atomically after acquire. - add @moonshot-ai/kernel-file-lock (fs-ext-extra-prebuilt; flock on unix, LockFileEx emulation on windows) - crossProcessLockService shrinks to try-acquire/checkHeld/release - minidb lockfile adopts the same flock-held semantics - delete processProbe
Resolve conflicts with #1888 (unified transcript layer, dropped /api/v2 RPC surface): - Accept main's deletion of the v2 ws transport (ws/eventMap, wsConnection, wsProtocol) and of the klient http/ws transports. - Drop the klient-side redirect pieces that only served the removed http transport (sessionRedirect, SessionRedirectChannel) and the v2 ownership-redirect e2e; the v1 REST redirect surface is untouched. - sessionEventBroadcaster: keep both the transcript additions and the ownership probe (getSubscriptionFailure); global events stay volatile (no __global__ journal) per the multi-instance design. - wsConnectionV1: combine typed subscription entries ({agentFilter, transcriptGrades}) with SkillCatalogBridge attach. - Restore klient's kap-server devDependency (removed on main); the dual-instance helpers still boot in-process servers. - workspaceFs tests: expect the <home>/sessions dir the always-on session-list watch creates at boot.
Contributor
|
❌ Nix build failed Hash mismatch in
Please update |
…ules Assert the ledger verdict in the fileFencing allow-path tests instead of relying on the helper-internal expect, and narrow firstFailure to an Error before rethrowing it from flushPersistence.
Conflicts resolved: - toolExecutor.ts: ToolCall import moved to #/kosong/contract/message (main's move) - start.ts: union of service imports; drop IModelCatalogService removed on main - ws/v1/events.ts: ProviderRefresh* types now from kosong/model/discovery - fileFencing.test.ts: ToolCall import updated likewise
Decouple the session file ledger from the fs watcher: verdicts come from a fresh stat-tuple compare immediately before execution, with no watcher ticks or cross-process file locks. Drop the dead dirty-tick and ensured-roots surface from the session fs watch service so it is only a confined, debounced change feed. Write fencing no longer keeps per-call target bookkeeping: the did-hook baselines the ledger from the revision the executed call attached to its own result. FileEditService verifies stat stability across the read-transform-write window.
- remove the unregistered-writer ownership variant and the dead session.list_changed / skill_catalog.changed zod schemas (no producers or runtime consumers) - unpublish CrossProcessLockService.acquireWithWait and KernelFileLockHandle.path; drop minidb's release() alias - converge duplicated assertScopeWritable, keyed-exclusion queue, special-file stat predicate, and stat-tuple comparison into shared helpers; import syncDir from agent-core-v2 in kap-server - extract a shared session-release hook for the three ws bridges and delegate resolveSessionOwnership to heldByPeerDetailsFromInspection - deduplicate test scaffolding (watch/authority/skill stubs, klient e2e helpers) and remove or merge duplicate test cases - revert unrelated formatting/comment churn and point design-doc references at section numbers instead of a local scratch path - merge the two overlapping lock changesets into one
Unify the four ino/mtimeMs/size comparators into _base's fileStatTuplesEqual, route persist.ts through the shared assertScopeWritable gate, share HELD_BY_PEER_CREATING_DETAILS between sessionLease and the lifecycle, extract dropCommittedLines in the journal and subscribe-ack/classify helpers in wsConnectionV1, and drop dead surface (unused PersistedWorkspaceFile export, unreachable fsWatch guard, inline lstat conversion, private isDir copy).
Net -40% PR test lines (7504 -> 4508) while keeping a verified probe for every failure mode the PR introduces: - delete harness self-tests and the subprocess e2e harness (klient dual-instance, spawn machinery) whose behavior is pinned by real scenario tests; cover holder-death lock release with a cheap SIGKILL unit test in kernel-file-lock instead - drop duplicate verdict-matrix variants, trivially-true assertions, and re-proven endpoint checks across fencing, ledger, journal, broadcaster, fs-watch, config, and web suites - compact shared rigs (sessionLease helpers, fileFencing/fileLedger slim DI wiring, broadcaster it.each + shared sessionEvents helper, ws-lifecycle shared setup) - sacrifice a documented set of sole-probe tests for volume (fsService gitignore cache, skill-listing reminder, kap-server ownership e2e, journal LAST-header/malformed-middle, cross-process wait/deadline paths); each is recoverable from history if the behavior regresses - add a held_by=peer ownership-join probe to kap-server sessions tests
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Related Issue
Follow-up to #1826. There is no single tracking issue for the remaining work; the problem and scope are described below.
Problem
Multiple Kimi Code servers can share one
KIMI_CODE_HOME, but several persistence and transport paths previously assumed a single process:Write/Editcalls had no session-local baseline for detecting an intervening filesystem change;The goal of this PR is to establish explicit ownership and durability boundaries for shared-home operation, while also tightening the single-instance journal and filesystem-watch paths those boundaries depend on.
What changed
Kernel-backed cross-process coordination
@moonshot-ai/kernel-file-lock, backed byfs-native-extensions, and wired its native dependency into the CLI bundle and Nix build.agent-core-v2CrossProcessLockService, using kernel-held file locks plus inode identity checks rather than heartbeat / TTL takeover.config.tomland workspace-registry read-modify-write operations behind cross-process locks while preserving their on-disk formats.Session ownership and release lifecycle
40921 SESSION_HELD_BY_PEERdetails for creating, routable, and local-holder states.Web and WebSocket convergence
40921outcomes in Kimi Web.session.list_changedhint and debounced Web list refresh when another instance creates, archives, or deletes a session.JournalStorageError, cold reads do not create files, and replay failures request a snapshot resync.Filesystem fencing, watching, and skill reload
Read,Write, andEditcalls record stat revisions;Write/Editcompare the current revision immediately before tool execution and block stale or read-before-write conflicts..gitignorereload handling, coalescing/truncation semantics, and the v1 WebSocket bridge.skill_catalog.changedWeb hint.Packaging and release notes
Verification
Known limitations and open review items
db.lockthrough the legacy PID-content protocol; rolling-upgrade compatibility still needs a dual-protocol boundary.Checklist
gen-changesetsskill, or this PR needs no changeset.gen-docsskill, or this PR needs no doc update. Documentation scope must be reassessed because the feature is no longer experimental.