= infra-tools-filesystem

== purpose

Provides three filesystem tool implementations for the Correx tool system: `FileReadTool` (read file content with optional line range), `FileWriteTool` (write or delete files with artifact capture via CAS), and `FileEditTool` (append, replace, or patch file content). All tools enforce path allowlisting and validate parameters before execution.

== responsibilities

* Read file contents with optional 1-indexed line range slicing
* Write content to files, optionally capturing artifacts to the CAS store
* Delete files on disk
* Edit files via three modes: append (add to end), replace (exact-target string replacement), patch (apply unified diff via external `patch` command)
* Validate paths against configured allowlists
* Report affected paths for sandbox backup/diff tracking

== non-responsibilities

* Do not implement sandboxed execution — that belongs to `infra:tools` (`SandboxedToolExecutor`)
* Do not define tool contracts — that belongs to `core:tools`
* Do not manage file permissions beyond optional POSIX mode setting
* Do not perform approval gating

== key types

=== FileReadTool
* **kind**: class
* **purpose**: Reads a file from disk within allowed paths, with optional start/end line range. Tier T1.
* **fields**: `allowedPaths` (set of permitted root directories)

=== FileWriteTool
* **kind**: class
* **purpose**: Writes content to a file or deletes a file, validates path against allowlist, optionally captures a `FileWrittenArtifact` to the CAS store. Tier T2.
* **fields**: `allowedPaths`, `artifactStore`, `materializingWriter`, `sandboxRoot`, `workingDir`

=== FileEditTool
* **kind**: class
* **purpose**: Edits a file via three operations: `append`, `replace` (exact single-occurrence string replacement), or `patch` (applies unified diff via external `patch` binary). Tier T3.
* **fields**: `allowedPaths`, `workingDir`

== event flow

*Inbound:* `ToolRequest` with parameters (`path`, `content`, `operation`, etc.)

*Outbound:* None directly. Event emission is handled by the wrapping `SandboxedToolExecutor`. The tools return `ToolResult.Success` or `ToolResult.Failure` synchronously.

== integration points

* `core:tools.contract` — `Tool`, `ToolExecutor`, `ToolResult`, `FileAffectingTool`, `ToolCapability`, `ValidationResult`
* `core:approvals` — `Tier`
* `core:artifactstore` — `ArtifactStore`
* `core:artifacts` — `MaterializingArtifactWriter`, `MaterializationResult`, `FileWrittenArtifact`, `FileWrittenPayload`
* `infra:artifacts-cas` — used by `FileWriteTool` for CAS artifact storage (via writer interface)

== invariants

* All tools validate path against allowed paths — if `allowedPaths` is empty, validation fails ("No paths are allowed")
* `FileWriteTool` prevents directory traversal via path normalization
* `FileEditTool.replace()` requires exactly one occurrence of the target string — zero or multiple occurrences produce a failure
* `FileEditTool.patch()` requires the external `patch` utility to be available
* All tools run on `Dispatchers.IO` for blocking filesystem operations

== PlantUML diagram

[plantuml, infra-tools-filesystem, "png"]
----
include::../../diagrams/infra-tools-filesystem.puml[]
----




== known issues

* `FileEditTool.patch()` shells out to the `patch` binary — not available on all platforms; no error if `patch` is missing beyond a failed `ProcessBuilder`
* `FileWriteTool.storeArtifact()` silently logs on materialization failure rather than failing the tool call
* `FileEditTool.replace()` reads the entire file into memory — unsuitable for very large files
* `FileWriteTool` and `FileEditTool` have duplicated path resolution logic

== open questions

* Should `FileEditTool` support a pure-Kotlin patching implementation to remove `patch` dependency?
* Should line-range edits (insert before/after line N) be added?
