Define ignored workspace routing semantics and budgets

This commit is contained in:
ms2k 2026-07-15 01:10:28 +09:00
commit c54372ea87
5 changed files with 905 additions and 0 deletions

View file

@ -655,6 +655,95 @@ environments, generated executables, caches, and other ignored artifacts from
later being executed by host tools. Trusted host configuration may disable this later being executed by host tools. Trusted host configuration may disable this
behavior when fully bidirectional ignored paths are required. behavior when fully bidirectional ignored paths are required.
#### Ignored Workspace State routing contract
The production router is a dedicated rootless host FUSE filesystem. It presents
one workspace tree and chooses exactly one backing for each pathname operation:
the canonical Agent Workspace for tracked and ordinary non-ignored paths, or the
Domain's Ignored Workspace State for ignored untracked paths. The `.git` entry is
host-backed, subject to the Git Sentry mounts below. Classification uses Git's
effective byte-path rules, including repository and nested `.gitignore` files,
negation and precedence, the applicable common-directory `info/exclude`, the
configured global excludes file, tracked-index state, linked worktrees, nested
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.
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.
A same-backing `rename` or hard link has the backing filesystem's atomicity and
error behavior. If the source and destination route to different backings,
`rename`, `RENAME_NOREPLACE`, `RENAME_EXCHANGE`, and hard link return `EXDEV`
before either backing is changed. `RENAME_WHITEOUT` returns `EOPNOTSUPP` without
mutation. Lazaret never reports a copy-and-unlink sequence as a successful
rename or a copied file as a hard link. 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
silent disappearance.
The v1 operation contract supports lookup, bytewise directory enumeration,
regular-file and directory creation, open, read, write, truncate, allocation,
sync, unlink, and same-backing rename and hard link. It supports symbolic links
without following a backing symlink during routing, nanosecond timestamps,
`user.*` extended attributes, POSIX ACLs where the backing filesystem supports
them, sparse-file hole/data queries and hole punching, same-backing copy range,
shared and private mappings, BSD `flock`, POSIX record locks, FIFOs, and Unix
domain sockets. Cross-backing copy range returns `EXDEV`. Character and block
device creation returns `EPERM`. Backing filesystems may return their native
documented unsupported error for an optional feature, but the router may not
turn a partial operation into success or fall through to the other backing.
The supported Git contract covers status, diff, ordinary add and reset, commit,
checkout and restore, branch and reference updates, merge, rebase, stash,
worktree-local index locking, linked worktrees, and nested repositories. These
operations retain Git's ordinary conflict and concurrent-writer behavior. Git
Sentry still makes host `.git/config` read-only and replaces default
`.git/hooks` with sandbox-local transient storage. Force-adding an isolated-only
path, cross-policy atomic rename, and device-node creation are refused as defined
above and are not compatibility promises.
The committed `lazaret-ignored-workspace-contract-v1` corpus is the executable
acceptance inventory for these semantics. It covers ignore precedence and live
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 absence of silent loss or copy-back.
The same corpus defines the benchmark protocol. Qualification runs direct-host
and routed placements on the recorded reference environment, uses identical
fresh fixture materialization for each sample, and reports both the routed
absolute median and the paired routed/direct median ratio. Metadata, Git, offline
package installation, and offline build workloads must meet both limits. The
reference environment, preparation states, sampling order, variance tolerance,
normalization, and numeric budgets are part of the corpus and may not be relaxed
by a production implementation.
Ignored-path isolation is defense in depth and does not replace the mandatory Git Ignored-path isolation is defense in depth and does not replace the mandatory Git
Sentry protections below. Sentry protections below.

View file

@ -0,0 +1,112 @@
{
"schema": "lazaret-ignored-workspace-benchmark-v1",
"reference_environment": {
"architecture": "x86_64",
"kernel": "Linux 6.9 or later",
"cpu": "reference x86_64 processor",
"cpu_set": "one hardware thread from each of eight physical cores",
"cpu_governor": "performance",
"memory_bytes": 17179869184,
"swap": "disabled-for-benchmark-cgroup",
"storage": "reference local NVMe-class block device",
"storage_stack": "NVMe with dm-crypt and no network or copy-on-write layer",
"filesystem": "XFS",
"filesystem_block_bytes": 4096,
"filesystem_mount_options": [
"rw",
"nosuid",
"nodev",
"relatime",
"inode64",
"noquota"
],
"fuse_userspace": "qualification-result-version",
"runsc": "qualification-result-version",
"git": "qualification-result-version",
"uv": "qualification-result-version",
"rust": "qualification-result-version"
},
"placements": {
"direct": "one native reference tree containing the same visible bytes and metadata on the same backing filesystem, without FUSE or runsc",
"routed": "the same backing filesystem through the production FUSE router and supported runsc"
},
"sampling": {
"independent_runs": 3,
"warmup_samples_per_cell": 2,
"measured_samples_per_cell": 15,
"order": "paired alternating direct-routed then routed-direct",
"clock": "CLOCK_MONOTONIC_RAW elapsed nanoseconds",
"statistic": "median",
"relative_statistic": "median of paired routed/direct elapsed-time ratios",
"outlier_policy": "retain every completed measured sample",
"sample_timeout": "four times the workload absolute budget",
"within_run_relative_mad_limit": 0.10,
"between_run_median_spread_limit": 0.10,
"budget_tolerance": 0.0
},
"preparation_states": {
"unprimed": "fresh uniquely named materialization, empty workload output directories, and no fixture prewalk; operating-system cache dropping is not required",
"primed": "fresh materialization followed by one untimed complete workload invocation before measured samples"
},
"normalization": {
"fixture_identity": "SHA-256 of canonical byte-path, kind, mode, size, and regular-file content records",
"result_identity": "workload-specific canonical output plus post-workload fixture identity",
"environment": "reject a run that differs from any reference environment field",
"background_load": "reject a sample when another process consumes more than five percent of one reference core or benchmark memory pressure causes reclaim",
"pass_rule": "every independent run and preparation state meets both the absolute median and paired median-ratio budget and both variance limits"
},
"workloads": [
{
"id": "metadata-10000",
"category": "metadata",
"fixture_seed": "b4e3a0d11bcd823e8ea7e9fc8a2e4ec4f4cb628e8df62df28ba369ecb2944dd7",
"fixture": "100 directories each containing 100 regular files of 64 bytes; half host-backed and half ignored isolated",
"fixture_algorithm": "directories d000 through d099; files f000 through f099; content is the 32-byte SHA-256 of fixture_seed, slash, and byte path repeated twice; even directories are host-backed and odd directories are ignored isolated",
"operation": "bytewise walk, lstat, open, read 64 bytes, close, and statx each file",
"command_sequence": [["lazaret-workspace-benchmark", "metadata", "--root", "ROOT", "--bytewise-order", "--statx-mask", "basic-stats"]],
"result_oracle": "exactly 10000 regular files, 640000 content bytes, and the canonical fixture identity",
"preparation_states": ["unprimed", "primed"],
"absolute_median_ms": 2000,
"relative_median_ratio": 25.0
},
{
"id": "git-2000-status-add-reset",
"category": "git",
"fixture_seed": "7ff9a3db8752e32d8d782c4c8d09d733be72f9dcba9d49d681b31193749f3ef4",
"fixture": "1000 tracked files, 500 ordinary untracked files, 500 ignored isolated files, and ignored host sentinels",
"fixture_algorithm": "tracked/t0000 through t0999 are committed; ordinary/u0000 through u0499 are untracked; ignored/i0000 through i0499 match one root ignore rule and have distinct host sentinel and isolated content derived from fixture_seed and byte path",
"operation": "porcelain-v2 status, add the ordinary untracked set, quiet mixed reset, and porcelain-v2 status",
"command_sequence": [["git", "status", "--porcelain=v2", "--untracked-files=all"], ["git", "add", "--", "ordinary"], ["git", "reset", "--quiet", "--mixed"], ["git", "status", "--porcelain=v2", "--untracked-files=all"]],
"result_oracle": "both status byte streams equal the locked direct placement streams, the index returns to its initial identity, and every ignored host sentinel is unchanged",
"preparation_states": ["unprimed", "primed"],
"absolute_median_ms": 2500,
"relative_median_ratio": 8.0
},
{
"id": "uv-offline-32-wheels",
"category": "package-manager",
"fixture_seed": "df5d5a7d287cc0a140d95c77a5f560db66929a138d5dfc854a6af4f90d609184",
"fixture": "one root wheel and 31 deterministic local dependency wheels with no build scripts or network access",
"fixture_algorithm": "packages lazaret-bench-pkg-00 through lazaret-bench-pkg-31 at version 1.0.0; package 00 depends exactly on packages 01 through 31; each pure-Python wheel contains one module whose VALUE is the SHA-256 of fixture_seed and normalized package name",
"operation": "uv pip install --offline --no-index into a fresh ignored virtual environment",
"command_sequence": [["uv", "pip", "install", "--offline", "--no-index", "--find-links", "WHEELHOUSE", "--python", "VENV/bin/python", "lazaret-bench-pkg-00==1.0.0"]],
"result_oracle": "all 32 exact distributions are installed and importing every module yields its fixture-derived VALUE",
"preparation_states": ["unprimed", "primed"],
"absolute_median_ms": 5000,
"relative_median_ratio": 6.0
},
{
"id": "cargo-offline-32-crates",
"category": "build",
"fixture_seed": "42324c58067ac0869fb4ec486f42fec74e0f3147a12aa2aee80af45c3bb8595d",
"fixture": "one binary and 31 path-library crates with deterministic generated Rust sources and an exact lockfile",
"fixture_algorithm": "workspace packages lazaret-bench-crate-00 through lazaret-bench-crate-31 at version 1.0.0; package 00 is a binary with exact path dependencies on libraries 01 through 31; each library returns the first eight bytes of SHA-256 of fixture_seed and package name as a u64 constant",
"operation": "cargo check --offline --locked --workspace with a fresh ignored target directory",
"command_sequence": [["cargo", "check", "--offline", "--locked", "--workspace", "--target-dir", "TARGET"]],
"result_oracle": "exit zero, no lockfile change, no source-tree change, and all output remains beneath the ignored target directory",
"preparation_states": ["unprimed", "primed"],
"absolute_median_ms": 8000,
"relative_median_ratio": 5.0
}
]
}

View file

@ -0,0 +1,228 @@
{
"schema": "lazaret-ignored-workspace-contract-v1",
"mechanism": "rootless-host-fuse-router",
"route_classes": [
"host",
"isolated"
],
"transition_contracts": [
{
"id": "cross-route-rename",
"operations": [
"rename",
"rename-noreplace",
"rename-exchange"
],
"result": "EXDEV",
"mutation": "none"
},
{
"id": "rename-whiteout",
"operations": [
"rename-whiteout"
],
"result": "EOPNOTSUPP",
"mutation": "none"
},
{
"id": "cross-route-hard-link",
"operations": [
"link"
],
"result": "EXDEV",
"mutation": "none"
},
{
"id": "ignored-to-host-policy",
"trigger": "path becomes non-ignored without becoming tracked",
"new_lookups": "host-or-absent",
"open_handles": "remain-isolated",
"isolated_state": "retained-hidden",
"copy": "none"
},
{
"id": "host-to-ignored-policy",
"trigger": "untracked path becomes ignored",
"new_lookups": "retained-isolated-or-absent",
"open_handles": "remain-host",
"host_state": "retained-hidden",
"copy": "none"
},
{
"id": "isolated-to-tracked-guest-publication",
"trigger": "guest index publication tracks an isolated-only path",
"result": "EBUSY",
"index_mutation": "none",
"isolated_state": "retained-visible",
"copy": "none"
},
{
"id": "isolated-to-tracked-host-established",
"trigger": "published index and type-compatible host object both exist",
"new_lookups": "host",
"open_handles": "remain-isolated",
"isolated_state": "retained-hidden",
"copy": "none"
},
{
"id": "isolated-to-tracked-unmediated-inconsistent",
"trigger": "unmediated index publication tracks a path without a host object",
"result": "EIO",
"path_state": "fail-closed-until-consistent",
"isolated_state": "retained-hidden-recoverable",
"copy": "none"
}
],
"filesystem_operations": [
{
"operation": "lookup-getattr-readdir",
"host": "supported",
"isolated": "supported",
"cross_route": "not-applicable"
},
{
"operation": "create-mkdir-open-read-write-truncate-fallocate-fsync",
"host": "supported",
"isolated": "supported",
"cross_route": "not-applicable"
},
{
"operation": "unlink-rmdir",
"host": "supported",
"isolated": "supported",
"cross_route": "not-applicable"
},
{
"operation": "rename",
"host": "supported",
"isolated": "supported",
"cross_route": "EXDEV"
},
{
"operation": "rename-noreplace",
"host": "supported",
"isolated": "supported",
"cross_route": "EXDEV"
},
{
"operation": "rename-exchange",
"host": "supported",
"isolated": "supported",
"cross_route": "EXDEV"
},
{
"operation": "rename-whiteout",
"host": "EOPNOTSUPP",
"isolated": "EOPNOTSUPP",
"cross_route": "EOPNOTSUPP"
},
{
"operation": "hard-link",
"host": "supported",
"isolated": "supported",
"cross_route": "EXDEV"
},
{
"operation": "symlink-readlink",
"host": "supported",
"isolated": "supported",
"cross_route": "virtual-path-resolution"
},
{
"operation": "user-xattrs",
"host": "backing-feature",
"isolated": "backing-feature",
"cross_route": "not-applicable"
},
{
"operation": "posix-acls",
"host": "backing-feature",
"isolated": "backing-feature",
"cross_route": "not-applicable"
},
{
"operation": "sparse-seek-hole-data-punch-hole",
"host": "backing-feature",
"isolated": "backing-feature",
"cross_route": "not-applicable"
},
{
"operation": "copy-file-range",
"host": "supported",
"isolated": "supported",
"cross_route": "EXDEV"
},
{
"operation": "utimens-nanoseconds",
"host": "supported",
"isolated": "supported",
"cross_route": "not-applicable"
},
{
"operation": "mmap-shared-private",
"host": "supported",
"isolated": "supported",
"cross_route": "pinned-open-backing"
},
{
"operation": "flock-posix-record-lock",
"host": "supported",
"isolated": "supported",
"cross_route": "pinned-open-backing"
},
{
"operation": "fifo-unix-socket",
"host": "supported",
"isolated": "supported",
"cross_route": "not-applicable"
},
{
"operation": "character-block-device-create",
"host": "EPERM",
"isolated": "EPERM",
"cross_route": "EPERM"
}
],
"git_compatibility": [
{
"operation": "status-diff",
"support": "supported"
},
{
"operation": "ordinary-add-reset-commit",
"support": "supported-host-backed-paths"
},
{
"operation": "checkout-restore",
"support": "supported"
},
{
"operation": "branch-reference-update",
"support": "supported"
},
{
"operation": "merge-rebase-stash",
"support": "supported"
},
{
"operation": "linked-worktree",
"support": "supported"
},
{
"operation": "nested-repository",
"support": "supported"
},
{
"operation": "force-add-isolated-only",
"support": "EBUSY-before-index-publication"
},
{
"operation": "host-config-write",
"support": "EROFS"
},
{
"operation": "default-hook-host-access",
"support": "sandbox-transient-only"
}
]
}

View file

@ -0,0 +1,246 @@
{
"schema": "lazaret-ignored-workspace-corpus-v1",
"path_encoding": "lowercase-hex-bytes",
"cases": [
{
"id": "non-utf8-ignore-match",
"tags": ["non-utf8-names", "ignore-precedence"],
"path_hex": "fffe2e6f626a",
"setup": ["root-ignore-star-dot-obj", "host-sentinel"],
"actions": ["sandbox-lookup", "sandbox-create"],
"expect": ["host-sentinel-hidden", "isolated-object-created"]
},
{
"id": "root-negation-precedence",
"tags": ["ignore-precedence", "negation"],
"path_hex": "6f75742f6b6565702e6c6f67",
"setup": ["ignore-out", "negate-keep-log"],
"actions": ["sandbox-write", "host-write"],
"expect": ["host-route", "bidirectional-visibility"]
},
{
"id": "nested-ignore-precedence",
"tags": ["ignore-precedence", "nested-ignore"],
"path_hex": "612f622f63616368652e62696e",
"setup": ["root-negation", "nested-ignore"],
"actions": ["sandbox-create"],
"expect": ["isolated-object-created", "host-path-absent"]
},
{
"id": "info-exclude",
"tags": ["ignore-precedence", "info-exclude"],
"path_hex": "6c6f63616c2e736563726574",
"setup": ["info-exclude-local-secret", "host-sentinel"],
"actions": ["sandbox-lookup"],
"expect": ["host-sentinel-hidden"]
},
{
"id": "global-excludes",
"tags": ["ignore-precedence", "global-excludes"],
"path_hex": "656469746f722e73776170",
"setup": ["global-exclude-star-dot-swap", "host-sentinel"],
"actions": ["sandbox-lookup"],
"expect": ["host-sentinel-hidden"]
},
{
"id": "ignore-case-folding",
"tags": ["core-ignore-case", "ignore-precedence"],
"path_hex": "4255494c442e4c4f47",
"setup": ["core-ignore-case-true", "ignore-build-log", "host-sentinel"],
"actions": ["sandbox-lookup"],
"expect": ["host-sentinel-hidden"]
},
{
"id": "linked-worktree-index",
"tags": ["worktrees", "git-status"],
"path_hex": "776f726b747265652d6361636865",
"setup": ["linked-worktree", "per-worktree-index", "ignored-host-sentinel"],
"actions": ["sandbox-git-status", "sandbox-create"],
"expect": ["correct-worktree-index", "host-sentinel-hidden"]
},
{
"id": "nested-repository-boundary",
"tags": ["nested-repositories", "ignore-precedence", "git-status"],
"path_hex": "76656e646f722f6e65737465642f7461726765742f6465627567",
"setup": ["nested-repository", "nested-ignore-target", "host-sentinel"],
"actions": ["sandbox-git-status", "sandbox-lookup"],
"expect": ["nested-rules-selected", "host-sentinel-hidden"]
},
{
"id": "live-ignore-publication",
"tags": ["ignore-precedence", "live-policy-change", "concurrent-mutation"],
"path_hex": "67656e6572617465642f6f7574707574",
"setup": ["host-object", "path-initially-non-ignored"],
"actions": ["host-publish-ignore", "sandbox-open-after-publication"],
"expect": ["single-classification-epoch", "host-object-hidden", "no-copy"]
},
{
"id": "cross-route-file-rename",
"tags": ["rename", "cross-policy-rename", "no-silent-loss"],
"path_hex": "7372632f746d70",
"setup": ["host-source", "ignored-destination"],
"actions": ["sandbox-rename"],
"expect": ["EXDEV", "source-unchanged", "destination-absent"]
},
{
"id": "cross-route-directory-exchange",
"tags": ["rename", "cross-policy-rename", "concurrent-mutation"],
"path_hex": "63616368652f73776170",
"setup": ["host-directory", "isolated-directory"],
"actions": ["sandbox-rename-exchange"],
"expect": ["EXDEV", "both-trees-unchanged"]
},
{
"id": "cross-route-hard-link",
"tags": ["link", "cross-policy-rename", "no-copy-back"],
"path_hex": "6275696c642f616c696173",
"setup": ["host-source", "ignored-destination"],
"actions": ["sandbox-hard-link"],
"expect": ["EXDEV", "destination-absent", "no-copy"]
},
{
"id": "ignored-becomes-non-ignored",
"tags": ["ignored-to-tracked-transition", "open-handle-transition", "no-copy-back"],
"path_hex": "63616368652f64617461",
"setup": ["isolated-object", "host-object", "open-isolated-handle"],
"actions": ["host-negate-ignore", "sandbox-open-new", "write-old-handle"],
"expect": ["new-handle-host", "old-handle-isolated", "no-copy", "both-objects-retained"]
},
{
"id": "non-ignored-becomes-ignored",
"tags": ["ignored-to-tracked-transition", "open-handle-transition", "no-copy-back"],
"path_hex": "6f75742f64617461",
"setup": ["host-object", "retained-isolated-object", "open-host-handle"],
"actions": ["host-publish-ignore", "sandbox-open-new", "write-old-handle"],
"expect": ["new-handle-isolated", "old-handle-host", "no-copy", "both-objects-retained"]
},
{
"id": "guest-force-add-isolated-only",
"tags": ["ignored-to-tracked-transition", "git-add", "no-silent-loss"],
"path_hex": "7461726765742f617070",
"setup": ["isolated-object", "path-ignored", "host-path-absent"],
"actions": ["sandbox-git-add-force"],
"expect": ["EBUSY-before-index-publication", "prior-index-retained", "isolated-object-visible", "host-path-absent"]
},
{
"id": "host-established-tracked-cutover",
"tags": ["ignored-to-tracked-transition", "open-handle-transition", "no-copy-back"],
"path_hex": "6173736574732f67656e657261746564",
"setup": ["isolated-object", "open-isolated-handle"],
"actions": ["host-create-type-compatible-object", "host-publish-tracked-index", "sandbox-open-new"],
"expect": ["new-handle-host", "old-handle-isolated", "isolated-object-retained-hidden", "no-copy"]
},
{
"id": "unmediated-inconsistent-index",
"tags": ["ignored-to-tracked-transition", "no-silent-loss", "concurrent-mutation"],
"path_hex": "646570732f6c6962",
"setup": ["isolated-object", "host-path-absent"],
"actions": ["host-publish-tracked-index", "sandbox-lookup"],
"expect": ["EIO", "path-fail-closed", "isolated-object-recoverable", "host-path-absent"]
},
{
"id": "mmap-policy-transition",
"tags": ["mmap", "open-handle-transition", "no-copy-back"],
"path_hex": "63616368652f6d6170706564",
"setup": ["isolated-object", "shared-write-mapping"],
"actions": ["host-negate-ignore", "mapped-write", "mapping-sync"],
"expect": ["isolated-object-updated", "host-object-unchanged", "no-copy"]
},
{
"id": "locks-policy-transition",
"tags": ["locks", "open-handle-transition"],
"path_hex": "63616368652f6c6f636b6564",
"setup": ["isolated-object", "isolated-posix-lock", "host-object"],
"actions": ["host-negate-ignore", "sandbox-open-new", "host-lock-attempt"],
"expect": ["old-lock-remains-isolated", "new-lock-domain-host", "no-lock-transfer"]
},
{
"id": "extended-attributes-and-acls",
"tags": ["xattrs", "acls"],
"path_hex": "63616368652f6d65746164617461",
"setup": ["host-and-isolated-backing-features"],
"actions": ["sandbox-set-get-remove-user-xattr", "sandbox-set-get-posix-acl"],
"expect": ["exact-selected-backing-metadata", "native-unsupported-errno-only"]
},
{
"id": "sparse-copy-range",
"tags": ["sparse", "copy-range"],
"path_hex": "6275696c642f737061727365",
"setup": ["isolated-sparse-source", "isolated-destination", "host-destination"],
"actions": ["seek-hole-data", "punch-hole", "same-route-copy-range", "cross-route-copy-range"],
"expect": ["sparse-extents-preserved", "same-route-bytes-match", "cross-route-EXDEV"]
},
{
"id": "symlink-confinement",
"tags": ["symlink", "concurrent-mutation"],
"path_hex": "63616368652f6c696e6b",
"setup": ["relative-symlink", "outside-looking-target", "rename-racer"],
"actions": ["sandbox-readlink", "sandbox-follow", "concurrent-backing-rename"],
"expect": ["link-bytes-preserved", "virtual-path-resolution", "no-backing-root-escape"]
},
{
"id": "timestamps",
"tags": ["timestamps"],
"path_hex": "7372632f74696d6564",
"setup": ["host-object"],
"actions": ["sandbox-utimens-nanoseconds", "host-stat"],
"expect": ["exact-supported-nanoseconds", "bidirectional-visibility"]
},
{
"id": "special-files",
"tags": ["special-files"],
"path_hex": "63616368652f7370656369616c",
"setup": ["isolated-directory"],
"actions": ["sandbox-create-fifo", "sandbox-bind-unix-socket", "sandbox-create-device"],
"expect": ["fifo-supported", "unix-socket-supported", "device-EPERM"]
},
{
"id": "directory-stream-policy-snapshot",
"tags": ["concurrent-mutation", "open-handle-transition", "ignore-precedence"],
"path_hex": "6f7574",
"setup": ["open-directory-stream", "host-and-isolated-children"],
"actions": ["host-publish-ignore-change", "continue-readdir", "open-new-directory-stream"],
"expect": ["old-stream-single-snapshot", "new-stream-new-snapshot", "no-duplicate-name"]
},
{
"id": "git-ordinary-workflow",
"tags": ["git-status", "git-add", "git-commit", "git-checkout"],
"path_hex": "7372632f6c69622e7273",
"setup": ["tracked-host-file", "ordinary-untracked-host-file"],
"actions": ["sandbox-git-status", "sandbox-git-add", "sandbox-git-commit", "sandbox-git-restore"],
"expect": ["host-index-and-objects-updated", "host-worktree-bidirectional", "ignored-sentinel-hidden"]
},
{
"id": "git-history-workflow",
"tags": ["git-merge", "git-rebase", "git-stash"],
"path_hex": "7372632f686973746f72792e7273",
"setup": ["two-host-backed-branches", "host-backed-local-change"],
"actions": ["sandbox-git-stash", "sandbox-git-merge", "sandbox-git-rebase"],
"expect": ["native-git-outcomes", "references-bidirectional", "no-isolated-copy-back"]
},
{
"id": "git-sentry",
"tags": ["git-config", "git-hooks", "git-status"],
"path_hex": "2e676974",
"setup": ["host-config-sentinel", "host-hook-sentinel"],
"actions": ["sandbox-write-git-config", "sandbox-write-default-hook", "sandbox-git-status"],
"expect": ["config-EROFS", "host-hook-hidden-unchanged", "sandbox-transient-hook", "git-status-supported"]
},
{
"id": "concurrent-host-sandbox-mutation",
"tags": ["concurrent-mutation", "rename", "no-silent-loss"],
"path_hex": "7372632f72616365",
"setup": ["host-backed-directory", "isolated-sibling"],
"actions": ["barrier-concurrent-host-replace", "sandbox-rename-write-unlink", "enumerate-both-backings"],
"expect": ["native-host-race-result", "isolated-state-intact", "no-duplicate-name", "no-cross-route-mutation"]
},
{
"id": "router-loss-fails-closed",
"tags": ["concurrent-mutation", "no-silent-loss", "no-copy-back"],
"path_hex": "63616368652f73656e74696e656c",
"setup": ["ignored-host-sentinel", "isolated-object", "mounted-router"],
"actions": ["terminate-router", "sandbox-lookup", "force-unmount", "inspect-backings"],
"expect": ["access-error-not-host-fallback", "host-sentinel-unchanged", "isolated-object-retained"]
}
]
}

View file

@ -0,0 +1,230 @@
from __future__ import annotations
import json
from pathlib import Path
import unittest
ROOT = Path(__file__).resolve().parents[2]
FIXTURE = ROOT / "tests/fixtures/ignored-workspace-v1"
def load(name: str) -> dict:
with (FIXTURE / name).open("rb") as source:
return json.load(source)
class IgnoredWorkspaceContractTests(unittest.TestCase):
def test_contract_dispatch_and_selected_mechanism_are_exact(self) -> None:
contract = load("contract.json")
self.assertEqual(contract["schema"], "lazaret-ignored-workspace-contract-v1")
self.assertEqual(contract["mechanism"], "rootless-host-fuse-router")
self.assertEqual(contract["route_classes"], ["host", "isolated"])
def test_cross_route_namespace_operations_refuse_before_mutation(self) -> None:
transitions = {
transition["id"]: transition
for transition in load("contract.json")["transition_contracts"]
}
for transition_id in (
"cross-route-rename",
"rename-whiteout",
"cross-route-hard-link",
):
with self.subTest(transition_id=transition_id):
self.assertEqual(transitions[transition_id]["mutation"], "none")
self.assertEqual(transitions["cross-route-rename"]["result"], "EXDEV")
self.assertEqual(transitions["cross-route-hard-link"]["result"], "EXDEV")
self.assertEqual(transitions["rename-whiteout"]["result"], "EOPNOTSUPP")
def test_transitions_never_copy_or_rebind_open_handles(self) -> None:
transitions = load("contract.json")["transition_contracts"]
copying = [
transition["id"]
for transition in transitions
if "copy" in transition and transition["copy"] != "none"
]
self.assertEqual(copying, [])
handle_transitions = {
transition["id"]: transition["open_handles"]
for transition in transitions
if "open_handles" in transition
}
self.assertEqual(
handle_transitions,
{
"ignored-to-host-policy": "remain-isolated",
"host-to-ignored-policy": "remain-host",
"isolated-to-tracked-host-established": "remain-isolated",
},
)
def test_isolated_only_force_add_is_explicitly_refused(self) -> None:
contract = load("contract.json")
transitions = {
transition["id"]: transition
for transition in contract["transition_contracts"]
}
transition = transitions["isolated-to-tracked-guest-publication"]
self.assertEqual(transition["result"], "EBUSY")
self.assertEqual(transition["index_mutation"], "none")
compatibility = {
operation["operation"]: operation["support"]
for operation in contract["git_compatibility"]
}
self.assertEqual(
compatibility["force-add-isolated-only"],
"EBUSY-before-index-publication",
)
def test_operation_matrix_covers_required_surface(self) -> None:
operations = {
operation["operation"]: operation
for operation in load("contract.json")["filesystem_operations"]
}
required = {
"lookup-getattr-readdir",
"create-mkdir-open-read-write-truncate-fallocate-fsync",
"rename",
"rename-noreplace",
"rename-exchange",
"rename-whiteout",
"hard-link",
"symlink-readlink",
"user-xattrs",
"posix-acls",
"sparse-seek-hole-data-punch-hole",
"copy-file-range",
"utimens-nanoseconds",
"mmap-shared-private",
"flock-posix-record-lock",
"fifo-unix-socket",
"character-block-device-create",
}
self.assertTrue(required.issubset(operations))
self.assertEqual(operations["rename"]["cross_route"], "EXDEV")
self.assertEqual(operations["hard-link"]["cross_route"], "EXDEV")
self.assertEqual(operations["copy-file-range"]["cross_route"], "EXDEV")
self.assertEqual(operations["character-block-device-create"]["host"], "EPERM")
def test_corpus_ids_and_byte_paths_are_canonical(self) -> None:
cases = load("corpus.json")["cases"]
ids = [case["id"] for case in cases]
self.assertEqual(len(ids), len(set(ids)))
for case in cases:
with self.subTest(case=case["id"]):
path_hex = case["path_hex"]
self.assertEqual(path_hex, path_hex.lower())
self.assertEqual(bytes.fromhex(path_hex).hex(), path_hex)
self.assertNotIn(b"\x00", bytes.fromhex(path_hex))
non_utf8 = next(case for case in cases if case["id"] == "non-utf8-ignore-match")
with self.assertRaises(UnicodeDecodeError):
bytes.fromhex(non_utf8["path_hex"]).decode("utf-8")
def test_corpus_covers_every_required_behavior(self) -> None:
cases = load("corpus.json")["cases"]
tags = {tag for case in cases for tag in case["tags"]}
required = {
"non-utf8-names",
"ignore-precedence",
"core-ignore-case",
"worktrees",
"nested-repositories",
"mmap",
"locks",
"xattrs",
"acls",
"sparse",
"copy-range",
"rename",
"link",
"symlink",
"timestamps",
"special-files",
"concurrent-mutation",
"cross-policy-rename",
"ignored-to-tracked-transition",
"open-handle-transition",
"no-silent-loss",
"no-copy-back",
}
self.assertTrue(required.issubset(tags), sorted(required - tags))
def test_corpus_asserts_backing_state_for_refusal_and_loss_cases(self) -> None:
cases = {case["id"]: case for case in load("corpus.json")["cases"]}
self.assertEqual(
cases["cross-route-file-rename"]["expect"],
["EXDEV", "source-unchanged", "destination-absent"],
)
self.assertIn("isolated-object-recoverable", cases["unmediated-inconsistent-index"]["expect"])
self.assertIn("access-error-not-host-fallback", cases["router-loss-fails-closed"]["expect"])
self.assertIn("host-sentinel-unchanged", cases["router-loss-fails-closed"]["expect"])
def test_benchmark_reference_conditions_are_complete(self) -> None:
reference = load("benchmark.json")["reference_environment"]
required = {
"architecture",
"kernel",
"cpu",
"cpu_set",
"cpu_governor",
"memory_bytes",
"swap",
"storage",
"storage_stack",
"filesystem",
"filesystem_block_bytes",
"filesystem_mount_options",
"fuse_userspace",
"runsc",
"git",
"uv",
"rust",
}
self.assertEqual(set(reference), required)
self.assertEqual(reference["architecture"], "x86_64")
self.assertEqual(reference["filesystem"], "XFS")
self.assertGreaterEqual(reference["memory_bytes"], 16 * 1024**3)
def test_sampling_protocol_fixes_statistics_and_variance(self) -> None:
sampling = load("benchmark.json")["sampling"]
self.assertEqual(sampling["independent_runs"], 3)
self.assertEqual(sampling["warmup_samples_per_cell"], 2)
self.assertEqual(sampling["measured_samples_per_cell"], 15)
self.assertEqual(sampling["statistic"], "median")
self.assertEqual(
sampling["relative_statistic"],
"median of paired routed/direct elapsed-time ratios",
)
self.assertEqual(sampling["outlier_policy"], "retain every completed measured sample")
self.assertLessEqual(sampling["within_run_relative_mad_limit"], 0.10)
self.assertLessEqual(sampling["between_run_median_spread_limit"], 0.10)
self.assertEqual(sampling["budget_tolerance"], 0.0)
def test_each_workload_has_absolute_and_relative_budgets(self) -> None:
benchmark = load("benchmark.json")
workloads = benchmark["workloads"]
self.assertEqual(
{workload["category"] for workload in workloads},
{"metadata", "git", "package-manager", "build"},
)
for workload in workloads:
with self.subTest(workload=workload["id"]):
self.assertGreater(workload["absolute_median_ms"], 0)
self.assertGreater(workload["relative_median_ratio"], 1.0)
self.assertEqual(workload["preparation_states"], ["unprimed", "primed"])
self.assertEqual(len(workload["fixture_seed"]), 64)
self.assertTrue(workload["fixture_algorithm"])
self.assertTrue(workload["command_sequence"])
self.assertTrue(all(command for command in workload["command_sequence"]))
self.assertTrue(workload["result_oracle"])
def test_specification_names_the_committed_contract(self) -> None:
specification = (ROOT / "docs/specification.md").read_text()
self.assertIn("#### Ignored Workspace State routing contract", specification)
self.assertIn("`lazaret-ignored-workspace-contract-v1`", specification)
self.assertIn("rootless host FUSE filesystem", specification)
if __name__ == "__main__":
unittest.main()