# Exploration: Mount Specificity Ordering ## Problem Statement When a tool instance uses both git repo mounts and regular file mounts, overlapping target paths can cause the broader mount to hide the more specific one. Example: - Git repo mount: `repo/x/` → `/workspace/x` (directory) - Regular file mount: `config.json` → `/workspace/x/y/config.json` (single file) Expected: `/workspace/x/y/config.json` contains the file mount contents. Actual: The git mount overwrites `/workspace/x`, hiding `/workspace/x/y/config.json`. ## Root Cause Docker Compose mounts volumes in the order they appear in the `volumes` array. In Linux, a later mount at a parent path hides earlier mounts at child paths. Current code ordering: 1. `compile_compose` adds manifest-defined mounts first 2. `EXTRA_VOLUMES` (profile + git mounts) appended after Within `EXTRA_VOLUMES` in `start_instance`: 1. `profile_mounts` from `apply_resolved_profile` 2. `git_mount_volumes` from `_resolve_git_mounts` Since git mounts are appended after regular mounts, a broad git mount (e.g. `/workspace/x`) overwrites a specific regular mount (e.g. `/workspace/x/y/config.json`). ## Affected Code Paths 1. **Manifest flow**: `compile_compose()` in `manifest_compiler.py` - Manifest mounts → `EXTRA_VOLUMES` - All appended to compose `volumes` list in that order 2. **Legacy flow**: `_modify_compose_file()` in `tool_instances.py` - Existing template volumes → `extra_volumes` appended - `extra_volumes` = profile_mounts + git_mount_volumes 3. **Both flows**: Volume entries are strings like `source:target` or `source:target:bind` - No structured sorting happens before write ## Options ### Option A: Sort by path depth (recommended) Sort all volume entries by target path specificity before writing compose. - Shorter / parent paths first - Deeper / child paths last - Deeper mounts "win" by being layered on top **Pros:** - Simple, predictable rule - Works for all mount types (manifest, git, profile, template) - Minimal code change **Cons:** - Sorting by string length is naive (edge cases with similar paths) - Need proper path-segment counting - Doesn't handle exact same target conflicts ### Option B: Detect and warn on overlaps Before writing compose, detect when any two mounts have overlapping target paths. Log a warning and optionally fail fast. **Pros:** - Surfaces conflicts to user early - No silent data loss **Cons:** - Doesn't actually fix the problem; user has to redesign mounts - False positives for legitimate use cases (mounting different files into same tree) ### Option C: Merge overlapping mounts into a single staging directory Instead of mounting multiple sources, stage all files into a single merged directory on disk, then mount that single directory. **Pros:** - Eliminates Docker mount ordering entirely - Natural specificity: later file writes overwrite earlier ones **Cons:** - Complex to implement correctly - Git mounts would need to be cloned into staging area - Breaks live file editing (bind mounts from host) - Large refactor ### Option D: Annotate mount specificity and merge in compiler Add a `priority` or `specificity` field to mount definitions. Compiler sorts by this field. **Pros:** - Explicit control **Cons:** - Adds schema complexity - Users must understand mount ordering - Overkill for this use case ## Recommendation **Option A** — sort by path depth. Rationale: - Mount specificity should "just work" without user intervention - Path depth is a natural proxy for specificity - A parent directory mount is almost always less specific than a child file mount - Implementation is ~20 lines in the compose write path - Can be combined with Option B (warn on exact conflicts) for safety ## Acceptance Criteria 1. A git repo mount to `/workspace/x` and a regular mount to `/workspace/x/y/config.json` both work: the config.json file contains the regular mount contents. 2. Multiple overlapping mounts sort consistently (deterministic). 3. Exact same-target conflicts are logged as warnings. 4. Both manifest and legacy flows behave correctly. 5. Unit tests cover overlap scenarios. ## Files to Modify - `apps/api/src/services/manifest_compiler.py` — `compile_compose()` sorting - `apps/api/src/api/tool_instances.py` — `_modify_compose_file()` sorting - `apps/api/tests/unit/test_manifest_compiler.py` — new tests - `apps/api/tests/unit/test_tool_instances.py` — new tests (or `test_tool_instances_legacy.py`)