Seal ignored-workspace routing at Domain startup

This commit is contained in:
ms2k 2026-07-30 00:52:58 +09:00
commit 1ad3b84db2

View file

@ -720,24 +720,34 @@ repositories, and `core.ignoreCase`. Non-UTF-8 path components are supported as
opaque bytes; NUL and `/` retain their ordinary pathname meaning and cannot be
components.
Each pathname operation uses one immutable classification snapshot. Publication
of a changed index or ignore input serializes against new pathname operations and
either installs one complete new snapshot or leaves the prior snapshot active.
There is no partially updated matcher. Existing file descriptions, mappings,
locks, and directory streams remain pinned to the backing object and snapshot
under which they were opened. A subsequent lookup or open uses the current
snapshot. Writes, flushes, locks, and mapping writeback through an old handle
affect only its original backing object; a transition never rebinds a handle or
copies its content to the other backing.
Domain initialization reads and seals one complete classification snapshot before
router readiness. Every pathname operation in that Domain generation uses the
sealed snapshot. Changes to an ignore file, repository configuration, global
excludes, nested-repository boundary, or Git index remain ordinary shared host
mutations but do not change routing in the running generation. There is no live
matcher publication and no partially updated matcher. File descriptions,
mappings, locks, and directory streams remain pinned to their original backing
objects for their lifetimes.
Directory lookup and enumeration expose only the entry selected by the current
snapshot. An ignored host entry is hidden even when no isolated entry exists. A
stale isolated entry is retained but hidden while its pathname is host-backed.
On a non-ignored-to-ignored transition, subsequent lookups expose the retained
isolated entry or absence and hide the host entry. On an
ignored-to-non-ignored transition, subsequent lookups expose the host entry or
absence and retain the isolated entry hidden. Neither transition imports,
exports, merges, deletes, or otherwise copies content between backings.
The router persists the admitted classification inputs in private Domain state.
Before admitting a later generation it compares the prior and candidate
classifiers across the host and isolated namespaces. A path ignored on first
admission starts absent in isolated state; corresponding host material is never
imported. A path that remains ignored preserves its isolated state. A path that
changes from host-backed to ignored is cloned from the current host object into
isolated state, replacing stale isolated state, while the host object remains
unchanged. A path that changes from ignored to host-backed has its isolated object
deleted before the host object or absence is exposed. Structural isolated
directories may remain only where required to reach descendants that are still
ignored.
Reconciliation completes before router readiness and publishes the candidate
policy only after the host inputs copied by the transition remain stable. A
failure or concurrent host mutation leaves the prior policy authoritative and
the generation unadmitted; a later initialization retries from that policy.
Recovery may repeat a clone or deletion, but never exports isolated bytes to the
host. No open handle spans a policy transition because transitions occur only
between Domain generations.
A same-backing `rename` or hard link has the backing filesystem's atomicity and
error behavior. An isolated-to-host rename, cross-backing hard link,
@ -792,17 +802,15 @@ processes that bypass FUSE.
All other cross-backing renames retain `EXDEV` behavior. Applications may react
to `EXDEV` with their own visible copy and unlink operations.
An index publication that would make an isolated object tracked is accepted only
when a type-compatible host worktree object already exists independently. The
router then selects that host object and retains the isolated object hidden; it
does not compare, merge, or copy isolated bytes. A guest index-lock rename that
would instead create a tracked path with only an isolated object returns `EBUSY`
before replacing the index. If an unmediated host index change creates that
state, pathname access to the inconsistent path fails with `EIO` until the host
index/worktree tuple is made consistent or reverted. The isolated object remains
recoverable Domain state. Consequently, ordinary add and commit are
supported for host-backed paths, while force-adding an isolated-only path is an
explicitly unsupported Git operation rather than implicit host copy-back or
An index publication in a running generation that newly tracks any path routed to
isolated state returns `EBUSY` before replacing the index, even when a
type-compatible host worktree object exists. Accepting it would change the
meaning of the shared index without changing the sealed route. Unmediated host
index changes likewise do not change routing in the running generation. On the
next initialization they participate in the candidate classifier and the same
between-generation reconciliation rules apply. Consequently, ordinary add and
commit are supported for host-backed paths, while force-adding a path routed to
isolated state is explicitly unsupported rather than implicit host copy-back or
silent disappearance.
The v1 operation contract supports lookup, bytewise directory enumeration,
@ -829,9 +837,9 @@ promises.
The repository `lazaret-ignored-workspace-contract-v1` corpus is a
non-authoritative executable test inventory derived from these semantics. It
covers ignore precedence and live changes, non-UTF-8 and case-folded matching,
covers ignore precedence and startup-sealed changes, non-UTF-8 and case-folded matching,
linked worktrees and nested repositories, every operation class above,
open-handle transitions, concurrent host and sandbox mutation, router loss, and
generation transitions, concurrent host and sandbox mutation, router loss, and
absence of silent loss or copy-back.
Its benchmark protocol compares direct-host and routed placements using identical
fresh fixture materialization and reports metadata, Git, offline package