Skip to content

feat(lattice): add ShadowFilesystem simulator for the v2 state lattice (closes #655)#668

Merged
SHAURYASANYAL3 merged 3 commits into
sreerevanth:mainfrom
SakethSumanBathini:feat/655-shadow-filesystem
Jul 26, 2026
Merged

feat(lattice): add ShadowFilesystem simulator for the v2 state lattice (closes #655)#668
SHAURYASANYAL3 merged 3 commits into
sreerevanth:mainfrom
SakethSumanBathini:feat/655-shadow-filesystem

Conversation

@SakethSumanBathini

@SakethSumanBathini SakethSumanBathini commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Summary

Phase 2 of the v2 state lattice (#651) needs a way to decide whether an agent's filesystem action is
safe by working out what it would do, rather than by pattern-matching the command that requests it.
This adds the filesystem half: ShadowFilesystem, an in-memory model that answers "what would this
action do?" without ever touching the disk.

Closes #655

What's here

agentwatch/lattice/shadow_filesystem.pyShadowFilesystem(root, known_paths) with:

  • simulate(action: FileAction) -> MutationResult — the method the issue asks for. Computes the
    normalised target path, the mutation type (CREATE / MODIFY / DELETE), and whether the target is
    a critical system path.
  • apply(action) — simulates and folds the outcome into the model, for reasoning about a
    sequence of actions where a file created in step 1 should read as an overwrite when step 2 writes to
    it again. Still no disk access.
  • exists(path) — whether the shadow tree believes a path exists.

MutationResult carries two fields beyond what the issue lists, because the lattice will need them:

  • existed_before — distinguishes a real delete from a no-op (deleting something that was never
    there), and a fresh write from an overwrite.
  • escapes_root — whether the target falls outside the workspace root, which is exactly what
    catches something like ../../etc/passwd reaching beyond where the action was scoped to run.

CRITICAL_SYSTEM_PATHS mirrors the set already used in agentwatch.core.blast_radius (/etc, /var,
/boot, /root, /home, /usr, /bin, /sbin) — checked directly rather than assumed, since a
docstring claiming that and being wrong would be worse than not claiming it.

The crucial constraint — proven, not asserted

The issue is explicit that the simulator must never execute real I/O. That's a test, not a comment:
test_no_filesystem_call_is_made_during_simulation wraps every filesystem entry point the class could
plausibly reach (Path.resolve, .exists, .stat, os.stat, os.listdir, builtins.open, and more)
in a recorder and asserts none of them fired while the simulator ran — including against a root that
doesn't exist on disk at all.

The design choice that makes this straightforward: path normalisation goes through os.path.normpath
(pure string work) rather than Path.resolve(), which stats the filesystem to follow symlinks.

A real cross-platform bug, found and fixed before merge

Running the suite on Windows caught something my Linux development environment couldn't:
_normalise() decided absoluteness with Path.is_absolute(), which is platform-dependent for a
POSIX-style path with no drive letter — PureWindowsPath("/etc/passwd").is_absolute() is False. That
made root / path join it as if it were relative, so on Windows /etc/passwd was silently folded into
a path underneath the workspace root, and both is_critical_path and escapes_root came back wrong.
For a simulator whose entire job is catching exactly this kind of dangerous absolute-path write, that
would have been a silent failure on the platform.

Fixed with a leading-slash string check instead of Path.is_absolute() — the paths this simulator
reasons about are POSIX paths regardless of what OS the lattice happens to run on. Verified directly
against PureWindowsPath semantics (not just re-run and hoped): the old code produced C:\etc\passwd
for that input, the new code produces \etc\passwd. There's a dedicated regression test for it, and the
existing Linux-side behaviour is unchanged.

Testing

pytest tests/test_shadow_filesystem.py34 passed, covering:

  • mutation type for write/append/mkdir/delete against known and unknown paths
  • relative-path resolution, ./.. collapsing, traversal out of the root
  • every entry in CRITICAL_SYSTEM_PATHS and its descendants flagged, ordinary paths not flagged, and a
    lookalike prefix (/etcetera) correctly not flagged
  • apply() sequencing (create → later write reads as modify; delete removes from the model)
  • simulate() alone leaving the model untouched
  • the no-real-I/O constraint, including against a nonexistent root
  • the Windows absolute-path regression above

pytest tests/ (full suite) — 116 failed / 816 passed, identical failure count to a clean run
without this module (missing optional deps — celery, redis, litellm, prometheus_client — in the
environment used to verify this), confirming zero regressions elsewhere.

ruff check, ruff format --check, mypy (on this module) — all clean. bandit — clean.

Scope

This is the filesystem shadow model only, matching the issue. Wiring it into the lattice's decision
layer, and any other resource types the lattice needs (network, process, etc.), are follow-up work under
#651.

Summary by CodeRabbit

  • New Features

    • Added an in-memory filesystem model for safely simulating file writes, modifications, deletions, and directory creation.
    • Added detection for critical system paths and operations that escape the configured workspace.
    • Added path normalization and disk-free existence checks for safer action evaluation.
  • Tests

    • Added coverage for mutation classification, path traversal, critical-path detection, sequential operations, and disk-free simulation.

@vercel

vercel Bot commented Jul 24, 2026

Copy link
Copy Markdown

@SakethSumanBathini is attempting to deploy a commit to the sreerevanth's projects Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@SakethSumanBathini, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 42 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 91512cc6-541b-449a-9e49-4e87773bc33b

📥 Commits

Reviewing files that changed from the base of the PR and between 5bef35d and 2c96984.

📒 Files selected for processing (2)
  • agentwatch/lattice/shadow_filesystem.py
  • tests/test_shadow_filesystem.py
📝 Walkthrough

Walkthrough

Adds a v2 in-memory ShadowFilesystem that classifies file mutations, detects critical or escaping paths, tracks simulated state, exposes public lattice symbols, and verifies disk-free behavior through comprehensive tests.

Changes

Shadow filesystem

Layer / File(s) Summary
Filesystem contracts and public API
agentwatch/lattice/shadow_filesystem.py, agentwatch/lattice/__init__.py
Defines file operations, mutation types, action/result dataclasses, critical paths, and package-level exports.
Simulation and in-memory state
agentwatch/lattice/shadow_filesystem.py
Normalizes paths without disk access, classifies mutations, evaluates safety flags, and updates simulated known paths.
Behavioral and I/O-free validation
tests/test_shadow_filesystem.py
Tests mutation classification, path handling, critical-path detection, state evolution, nonexistent roots, and the simulation I/O ban.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Poem

A bunny hops through paths unseen,
With shadow files in memory green.
CREATE and DELETE dance in flight,
Critical roots stay marked just right.
No disk is touched beneath the moon—
Tests hum a gentle lattice tune.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly names the main change: adding the ShadowFilesystem simulator for the v2 state lattice.
Linked Issues check ✅ Passed ShadowFilesystem with root-scoped simulate() returns target path, mutation type, and critical-path status without real disk I/O.
Out of Scope Changes check ✅ Passed The changes stay focused on the filesystem simulator, its exports, and tests, with no unrelated additions.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

🧪 PR Test Results

Check Result
Tests (pytest tests/) ✅ success
Lint (ruff check .) ✅ success
Coverage (agentwatch) 74.14%

Python 3.12 · commit 2c96984

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@agentwatch/lattice/shadow_filesystem.py`:
- Around line 94-117: Fix ShadowFilesystem.__init__ so a relative root cannot
produce a duplicated or non-absolute self.root: either validate Path(root) is
absolute and fail clearly, or resolve it against an explicit absolute anchor
before calling _normalise. Ensure known_paths continue to normalize against the
resulting self.root and preserve the existing absolute-root behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 90262a20-af7d-4b2b-bf29-2cfe65c34713

📥 Commits

Reviewing files that changed from the base of the PR and between 0a2e15f and 5bef35d.

📒 Files selected for processing (3)
  • agentwatch/lattice/__init__.py
  • agentwatch/lattice/shadow_filesystem.py
  • tests/test_shadow_filesystem.py

Comment thread agentwatch/lattice/shadow_filesystem.py

@SHAURYASANYAL3 SHAURYASANYAL3 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, very clean and adheres to V2 constraints. Approving!

@SHAURYASANYAL3
SHAURYASANYAL3 merged commit d94dfd0 into sreerevanth:main Jul 26, 2026
14 of 15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[v2] Implement ShadowFilesystem Simulator

2 participants