Repository: cognitive-engineering-lab/aquascope (language: rust)

Issue:
Ch 4.2 code block examples with permission annotations use path in tooltips instead of place
- I have searched open and closed issues and pull requests for duplicates, using these search terms:
  -  path place
- I have checked the latest `main` branch to see if this has already been fixed, in this file:
  - https://github.com/cognitive-engineering-lab/rust-book/blob/main/src/ch04-02-references-and-borrowing.md

URL to the section(s) of the book with this problem:
- https://rust-book.cs.brown.edu/ch04-02-references-and-borrowing.html#mutable-references-provide-unique-and-non-owning-access-to-data
- Also applies to other sections with the dynamic annotation to the code blocks

Description of the problem:
In previous issues/PRs (#176 cognitive-engineering-lab/rust-book#211) the wording was changed to move to the use of place over path, however these same changes were not applied to the components used to annotated the code blocks. In particular the tooltips still refer to paths instead of places so it felt confusing to see that term when it is not used elsewhere in this chapter.

Suggested fix:
Change the tooltips and any parts of the permission annotation components to use place instead of path. I really like the annotations, I just got confused with the mixed use of path and place


Discussion / hints:

Fix patch:
diff --git a/.dockerignore b/.dockerignore
deleted file mode 100644
index d1da287bd..000000000
--- a/.dockerignore
+++ /dev/null
@@ -1,2 +0,0 @@
-frontend
-**/target
diff --git a/.github/workflows/standalone.yml b/.github/workflows/standalone.yml
index c71cf64b2..7c88dc629 100644
--- a/.github/workflows/standalone.yml
+++ b/.github/workflows/standalone.yml
@@ -1,27 +1,27 @@
-# TODO: automatically publish WASM port (somehow...)
 name: standalone
 
-# on:
-#   pull_request:
-#     branches: [main]
-#     types: [labeled,closed]
+on:
+  pull_request:
+    branches: [standalone-wasm]
+    types: [labeled,closed]
 
-# jobs:
-#   update-frontend:
-#     needs: publish-crates
-#     runs-on: ubuntu-latest
-#     steps:
-#       - uses: actions/checkout@v3
-#       - uses: DeterminateSystems/nix-installer-action@main
-#       - uses: DeterminateSystems/magic-nix-cache-action@main
-#       - uses: DeterminateSystems/flake-checker-action@main
+ jobs:
+  update-frontend:
+    needs: publish-crates
+    runs-on: ubuntu-latest
+    if: false # disable for now
+    steps:
+      - uses: actions/checkout@v3
+      - uses: DeterminateSystems/nix-installer-action@main
+      - uses: DeterminateSystems/magic-nix-cache-action@main
+      - uses: DeterminateSystems/flake-checker-action@main
 
-#       - name: Build Docs and Standalone
-#         run: nix develop .#minimal --command ci-build-pages
+      - name: Build Docs and Standalone
+        run: nix develop .#minimal --command ci-build-pages
 
-#       - uses: JamesIves/github-pages-deploy-action@v4.3.0
-#         with:
-#           branch: gh-pages
-#           folder: ./frontend/packages/aquascope-standalone/dist
-#           clean: true
-#           clean-exclude: dev
+      - uses: JamesIves/github-pages-deploy-action@v4.3.0
+        with:
+          branch: gh-pages
+          folder: ./frontend/packages/aquascope-standalone/dist
+          clean: true
+          clean-exclude: dev
diff --git a/Caddyfile b/Caddyfile
deleted file mode 100644
index e952519e0..000000000
--- a/Caddyfile
+++ /dev/null
@@ -1,7 +0,0 @@
-aquascope.willcrichton.net
-
-reverse_proxy :8008
-
-log {
-    output file /var/log/caddy/access.log
-}
diff --git a/Cargo.lock b/Cargo.lock
index 562f76d80..83d904614 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1,6 +1,6 @@
 # This file is automatically @generated by Cargo.
 # It is not intended for manual editing.
-version = 3
+version = 4
 
 [[package]]
 name = "Inflector"
@@ -10,24 +10,35 @@ checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3"
 
 [[package]]
 name = "addr2line"
-version = "0.21.0"
+version = "0.24.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
+checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
 dependencies = [
  "gimli",
 ]
 
 [[package]]
-name = "adler"
-version = "1.0.2"
+name = "adler2"
+version = "2.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
+checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
+
+[[package]]
+name = "aes"
+version = "0.8.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0"
+dependencies = [
+ "cfg-if",
+ "cipher",
+ "cpufeatures",
+]
 
 [[package]]
 name = "aho-corasick"
-version = "1.0.5"
+version = "1.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0c378d78423fdad8089616f827526ee33c19f2fddbd5de1629152c9593ba4783"
+checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
 dependencies = [
  "memchr",
 ]
@@ -56,34 +67,49 @@ dependencies = [
  "anstyle",
  "anstyle-parse",
  "anstyle-query",
- "anstyle-wincon",
+ "anstyle-wincon 1.0.2",
  "colorchoice",
  "is-terminal",
  "utf8parse",
 ]
 
+[[package]]
+name = "anstream"
+version = "0.6.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
+dependencies = [
+ "anstyle",
+ "anstyle-parse",
+ "anstyle-query",
+ "anstyle-wincon 3.0.6",
+ "colorchoice",
+ "is_terminal_polyfill",
+ "utf8parse",
+]
+
 [[package]]
 name = "anstyle"
-version = "1.0.2"
+version = "1.0.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "15c4c2c83f81532e5845a733998b6971faca23490340a418e9b72a3ec9de12ea"
+checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
 
 [[package]]
 name = "anstyle-parse"
-version = "0.2.1"
+version = "0.2.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333"
+checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
 dependencies = [
  "utf8parse",
 ]
 
 [[package]]
 name = "anstyle-query"
-version = "1.0.0"
+version = "1.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
+checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
 dependencies = [
- "windows-sys 0.48.0",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
@@ -96,11 +122,21 @@ dependencies = [
  "windows-sys 0.48.0",
 ]
 
+[[package]]
+name = "anstyle-wincon"
+version = "3.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125"
+dependencies = [
+ "anstyle",
+ "windows-sys 0.59.0",
+]
+
 [[package]]
 name = "anyhow"
-version = "1.0.75"
+version = "1.0.95"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
+checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04"
 
 [[package]]
 name = "aquascope"
@@ -111,6 +147,7 @@ dependencies = [
  "aquascope_workspace_utils",
  "env_logger 0.9.3",
  "fluid-let",
+ "fuzzy_match",
  "insta",
  "itertools",
  "lazy_static",
@@ -120,7 +157,7 @@ dependencies = [
  "rustc_utils",
  "serde",
  "test-log",
- "ts-rs",
+ "ts-rs 7.1.1",
 ]
 
 [[package]]
@@ -138,19 +175,19 @@ dependencies = [
  "rustc_utils",
  "serde",
  "serde_json",
- "ts-rs",
+ "ts-rs 6.2.1",
 ]
 
 [[package]]
 name = "aquascope_serve"
 version = "0.1.0"
 dependencies = [
+ "anyhow",
+ "aquascope_workspace_utils",
  "async-trait",
  "axum",
- "bollard",
  "env_logger 0.9.3",
  "futures",
- "lazy_static",
  "log",
  "serde",
  "serde_json",
@@ -172,13 +209,13 @@ dependencies = [
 
 [[package]]
 name = "async-trait"
-version = "0.1.73"
+version = "0.1.83"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0"
+checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.29",
+ "syn 2.0.93",
 ]
 
 [[package]]
@@ -194,9 +231,9 @@ dependencies = [
 
 [[package]]
 name = "autocfg"
-version = "1.1.0"
+version = "1.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
+checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
 
 [[package]]
 name = "axum"
@@ -247,25 +284,19 @@ dependencies = [
 
 [[package]]
 name = "backtrace"
-version = "0.3.69"
+version = "0.3.74"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837"
+checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a"
 dependencies = [
  "addr2line",
- "cc",
  "cfg-if",
  "libc",
  "miniz_oxide",
  "object",
  "rustc-demangle",
+ "windows-targets 0.52.6",
 ]
 
-[[package]]
-name = "base64"
-version = "0.13.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
-
 [[package]]
 name = "bitflags"
 version = "1.3.2"
@@ -274,9 +305,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
 
 [[package]]
 name = "bitflags"
-version = "2.4.0"
+version = "2.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
+checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
 
 [[package]]
 name = "block-buffer"
@@ -287,78 +318,46 @@ dependencies = [
  "generic-array",
 ]
 
-[[package]]
-name = "bollard"
-version = "0.13.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d82e7850583ead5f8bbef247e2a3c37a19bd576e8420cd262a6711921827e1e5"
-dependencies = [
- "base64",
- "bollard-stubs",
- "bytes",
- "futures-core",
- "futures-util",
- "hex",
- "http",
- "hyper",
- "hyperlocal",
- "log",
- "pin-project-lite",
- "serde",
- "serde_derive",
- "serde_json",
- "serde_urlencoded",
- "thiserror",
- "tokio",
- "tokio-util",
- "url",
- "winapi",
-]
-
-[[package]]
-name = "bollard-stubs"
-version = "1.42.0-rc.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed59b5c00048f48d7af971b71f800fdf23e858844a6f9e4d32ca72e9399e7864"
-dependencies = [
- "serde",
- "serde_with",
-]
-
 [[package]]
 name = "bstr"
-version = "1.6.2"
+version = "1.11.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4c2f7349907b712260e64b0afe2f84692af14a454be26187d9df565c7f69266a"
+checksum = "786a307d683a5bf92e6fd5fd69a7eb613751668d1d8d67d802846dfe367c62c8"
 dependencies = [
  "memchr",
- "regex-automata",
+ "regex-automata 0.4.9",
  "serde",
 ]
 
 [[package]]
 name = "bumpalo"
-version = "3.13.0"
+version = "3.16.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1"
+checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
 
 [[package]]
 name = "bytecount"
-version = "0.6.3"
+version = "0.6.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2c676a478f63e9fa2dd5368a42f28bba0d6c560b775f38583c8bbaa7fcd67c9c"
+checksum = "5ce89b21cab1437276d2650d57e971f9d548a2d9037cc231abdc0562b97498ce"
+
+[[package]]
+name = "byteorder"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
 
 [[package]]
 name = "bytes"
-version = "1.4.0"
+version = "1.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be"
+checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b"
 
 [[package]]
 name = "camino"
-version = "1.1.6"
+version = "1.1.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c"
+checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3"
 dependencies = [
  "serde",
 ]
@@ -380,18 +379,18 @@ checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa"
 dependencies = [
  "camino",
  "cargo-platform",
- "semver",
+ "semver 1.0.20",
  "serde",
  "serde_json",
 ]
 
 [[package]]
 name = "cc"
-version = "1.0.83"
+version = "1.2.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
+checksum = "8d6dbb628b8f8555f86d0323c2eb39e3ec81901f4b83e091db8a6a76d316a333"
 dependencies = [
- "libc",
+ "shlex",
 ]
 
 [[package]]
@@ -402,9 +401,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "chrono"
-version = "0.4.38"
+version = "0.4.39"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401"
+checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825"
 dependencies = [
  "android-tzdata",
  "iana-time-zone",
@@ -414,6 +413,37 @@ dependencies = [
  "windows-targets 0.52.6",
 ]
 
+[[package]]
+name = "chrono-tz"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cd6dd8046d00723a59a2f8c5f295c515b9bb9a331ee4f8f3d4dd49e428acd3b6"
+dependencies = [
+ "chrono",
+ "chrono-tz-build",
+ "phf",
+]
+
+[[package]]
+name = "chrono-tz-build"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e94fea34d77a245229e7746bd2beb786cd2a896f306ff491fb8cecb3074b10a7"
+dependencies = [
+ "parse-zoneinfo",
+ "phf_codegen",
+]
+
+[[package]]
+name = "cipher"
+version = "0.4.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
+dependencies = [
+ "crypto-common",
+ "inout",
+]
+
 [[package]]
 name = "clap"
 version = "3.2.25"
@@ -445,7 +475,7 @@ version = "4.3.24"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5ed2e96bc16d8d740f6f48d663eddf4b8a0983e79210fd55479b7bcd0a69860e"
 dependencies = [
- "anstream",
+ "anstream 0.3.2",
  "anstyle",
  "clap_lex 0.5.1",
  "once_cell",
@@ -455,9 +485,9 @@ dependencies = [
 
 [[package]]
 name = "clap_complete"
-version = "4.4.0"
+version = "4.5.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "586a385f7ef2f8b4d86bddaa0c094794e7ccbfe5ffef1f434fe928143fc783a5"
+checksum = "b5a2d6eec27fce550d708b2be5d798797e5a55b246b323ef36924a0001996352"
 dependencies = [
  "clap 4.3.24",
 ]
@@ -484,7 +514,7 @@ dependencies = [
  "heck",
  "proc-macro2",
  "quote",
- "syn 2.0.29",
+ "syn 2.0.93",
 ]
 
 [[package]]
@@ -504,88 +534,70 @@ checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961"
 
 [[package]]
 name = "colorchoice"
-version = "1.0.0"
+version = "1.0.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
+checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
 
 [[package]]
 name = "console"
-version = "0.15.7"
+version = "0.15.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c926e00cc70edefdc64d3a5ff31cc65bb97a3460097762bd23afb4d8145fccf8"
+checksum = "ea3c6ecd8059b57859df5c69830340ed3c41d30e3da0c1cbed90a96ac853041b"
 dependencies = [
  "encode_unicode",
- "lazy_static",
  "libc",
- "windows-sys 0.45.0",
+ "once_cell",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
 name = "core-foundation-sys"
-version = "0.8.4"
+version = "0.8.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
+checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
 
 [[package]]
 name = "cpufeatures"
-version = "0.2.9"
+version = "0.2.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1"
+checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3"
 dependencies = [
  "libc",
 ]
 
 [[package]]
 name = "crc32fast"
-version = "1.3.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
-dependencies = [
- "cfg-if",
-]
-
-[[package]]
-name = "crossbeam-channel"
-version = "0.5.8"
+version = "1.4.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200"
+checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
 dependencies = [
  "cfg-if",
- "crossbeam-utils",
 ]
 
 [[package]]
 name = "crossbeam-deque"
-version = "0.8.3"
+version = "0.8.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef"
+checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
 dependencies = [
- "cfg-if",
  "crossbeam-epoch",
  "crossbeam-utils",
 ]
 
 [[package]]
 name = "crossbeam-epoch"
-version = "0.9.15"
+version = "0.9.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7"
+checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
 dependencies = [
- "autocfg",
- "cfg-if",
  "crossbeam-utils",
- "memoffset",
- "scopeguard",
 ]
 
 [[package]]
 name = "crossbeam-utils"
-version = "0.8.16"
+version = "0.8.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294"
-dependencies = [
- "cfg-if",
-]
+checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
 
 [[package]]
 name = "crypto-common"
@@ -598,58 +610,34 @@ dependencies = [
 ]
 
 [[package]]
-name = "ctrlc"
-version = "3.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "82e95fbd621905b854affdc67943b043a0fbb6ed7385fd5a25650d19a8a6cfdf"
-dependencies = [
- "nix",
- "windows-sys 0.48.0",
-]
-
-[[package]]
-name = "darling"
-version = "0.13.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c"
-dependencies = [
- "darling_core",
- "darling_macro",
-]
-
-[[package]]
-name = "darling_core"
-version = "0.13.4"
+name = "digest"
+version = "0.10.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610"
+checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
 dependencies = [
- "fnv",
- "ident_case",
- "proc-macro2",
- "quote",
- "strsim",
- "syn 1.0.109",
+ "block-buffer",
+ "crypto-common",
 ]
 
 [[package]]
-name = "darling_macro"
-version = "0.13.4"
+name = "directories"
+version = "5.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835"
+checksum = "9a49173b84e034382284f27f1af4dcbbd231ffa358c0fe316541a7337f376a35"
 dependencies = [
- "darling_core",
- "quote",
- "syn 1.0.109",
+ "dirs-sys",
 ]
 
 [[package]]
-name = "digest"
-version = "0.10.7"
+name = "dirs-sys"
+version = "0.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
+checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c"
 dependencies = [
- "block-buffer",
- "crypto-common",
+ "libc",
+ "option-ext",
+ "redox_users",
+ "windows-sys 0.48.0",
 ]
 
 [[package]]
@@ -660,15 +648,24 @@ checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
 
 [[package]]
 name = "either"
-version = "1.9.0"
+version = "1.13.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
+checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
 
 [[package]]
 name = "encode_unicode"
-version = "0.3.6"
+version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
+checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0"
+
+[[package]]
+name = "env_filter"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0"
+dependencies = [
+ "log",
+]
 
 [[package]]
 name = "env_logger"
@@ -685,9 +682,9 @@ dependencies = [
 
 [[package]]
 name = "env_logger"
-version = "0.10.0"
+version = "0.10.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0"
+checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580"
 dependencies = [
  "humantime",
  "is-terminal",
@@ -696,6 +693,18 @@ dependencies = [
  "termcolor",
 ]
 
+[[package]]
+name = "env_logger"
+version = "0.11.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dcaee3d8e3cfc3fd92428d477bc97fc29ec8716d180c0d74c643bb26166660e0"
+dependencies = [
+ "anstream 0.6.18",
+ "anstyle",
+ "env_filter",
+ "log",
+]
+
 [[package]]
 name = "equivalent"
 version = "1.0.1"
@@ -704,48 +713,37 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
 
 [[package]]
 name = "errno"
-version = "0.3.3"
+version = "0.3.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "136526188508e25c6fef639d7927dfb3e0e3084488bf202267829cf7fc23dbdd"
+checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d"
 dependencies = [
- "errno-dragonfly",
- "libc",
- "windows-sys 0.48.0",
-]
-
-[[package]]
-name = "errno-dragonfly"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
-dependencies = [
- "cc",
  "libc",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
 name = "fastrand"
-version = "2.0.0"
+version = "2.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764"
+checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
 
 [[package]]
 name = "filetime"
-version = "0.2.22"
+version = "0.2.25"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d4029edd3e734da6fe05b6cd7bd2960760a616bd2ddd0d59a0124746d6272af0"
+checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586"
 dependencies = [
  "cfg-if",
  "libc",
- "redox_syscall 0.3.5",
- "windows-sys 0.48.0",
+ "libredox",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
 name = "flate2"
-version = "1.0.27"
+version = "1.0.35"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c6c98ee8095e9d1dcbf2fcc6d95acccb90d1c81db1e44725c6a984b1dbdfb010"
+checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c"
 dependencies = [
  "crc32fast",
  "miniz_oxide",
@@ -765,18 +763,18 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
 
 [[package]]
 name = "form_urlencoded"
-version = "1.2.0"
+version = "1.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652"
+checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
 dependencies = [
  "percent-encoding",
 ]
 
 [[package]]
 name = "futures"
-version = "0.3.28"
+version = "0.3.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40"
+checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876"
 dependencies = [
  "futures-channel",
  "futures-core",
@@ -789,9 +787,9 @@ dependencies = [
 
 [[package]]
 name = "futures-channel"
-version = "0.3.28"
+version = "0.3.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2"
+checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
 dependencies = [
  "futures-core",
  "futures-sink",
@@ -799,15 +797,15 @@ dependencies = [
 
 [[package]]
 name = "futures-core"
-version = "0.3.28"
+version = "0.3.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c"
+checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
 
 [[package]]
 name = "futures-executor"
-version = "0.3.28"
+version = "0.3.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0"
+checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f"
 dependencies = [
  "futures-core",
  "futures-task",
@@ -816,38 +814,38 @@ dependencies = [
 
 [[package]]
 name = "futures-io"
-version = "0.3.28"
+version = "0.3.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964"
+checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
 
 [[package]]
 name = "futures-macro"
-version = "0.3.28"
+version = "0.3.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72"
+checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.29",
+ "syn 2.0.93",
 ]
 
 [[package]]
 name = "futures-sink"
-version = "0.3.28"
+version = "0.3.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e"
+checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7"
 
 [[package]]
 name = "futures-task"
-version = "0.3.28"
+version = "0.3.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65"
+checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
 
 [[package]]
 name = "futures-util"
-version = "0.3.28"
+version = "0.3.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533"
+checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
 dependencies = [
  "futures-channel",
  "futures-core",
@@ -861,6 +859,16 @@ dependencies = [
  "slab",
 ]
 
+[[package]]
+name = "fuzzy_match"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5f018ca9f4ec5fd881ecc3ec3970cbb2f68ce539aeef7ccdf528d2669a1c16e8"
+dependencies = [
+ "rustc_version",
+ "sliding_windows",
+]
+
 [[package]]
 name = "generic-array"
 version = "0.14.7"
@@ -873,9 +881,9 @@ dependencies = [
 
 [[package]]
 name = "getrandom"
-version = "0.2.10"
+version = "0.2.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
+checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
 dependencies = [
  "cfg-if",
  "libc",
@@ -884,41 +892,22 @@ dependencies = [
 
 [[package]]
 name = "gimli"
-version = "0.28.0"
+version = "0.31.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0"
-
-[[package]]
-name = "h2"
-version = "0.3.21"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "91fc23aa11be92976ef4729127f1a74adf36d8436f7816b185d18df956790833"
-dependencies = [
- "bytes",
- "fnv",
- "futures-core",
- "futures-sink",
- "futures-util",
- "http",
- "indexmap 1.9.3",
- "slab",
- "tokio",
- "tokio-util",
- "tracing",
-]
+checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
 
 [[package]]
 name = "handlebars"
-version = "4.4.0"
+version = "4.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c39b3bc2a8f715298032cf5087e58573809374b08160aa7d750582bdb82d2683"
+checksum = "faa67bab9ff362228eb3d00bd024a4965d8231bbb7921167f0cfa66c6626b225"
 dependencies = [
  "log",
  "pest",
  "pest_derive",
  "serde",
  "serde_json",
- "thiserror",
+ "thiserror 1.0.69",
 ]
 
 [[package]]
@@ -929,9 +918,9 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
 
 [[package]]
 name = "hashbrown"
-version = "0.14.0"
+version = "0.15.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a"
+checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
 
 [[package]]
 name = "heck"
@@ -950,15 +939,15 @@ dependencies = [
 
 [[package]]
 name = "hermit-abi"
-version = "0.3.2"
+version = "0.3.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b"
+checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
 
 [[package]]
-name = "hex"
-version = "0.4.3"
+name = "hermit-abi"
+version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
+checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc"
 
 [[package]]
 name = "html-escape"
@@ -971,9 +960,9 @@ dependencies = [
 
 [[package]]
 name = "http"
-version = "0.2.9"
+version = "0.2.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482"
+checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1"
 dependencies = [
  "bytes",
  "fnv",
@@ -982,9 +971,9 @@ dependencies = [
 
 [[package]]
 name = "http-body"
-version = "0.4.5"
+version = "0.4.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1"
+checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2"
 dependencies = [
  "bytes",
  "http",
@@ -999,9 +988,9 @@ checksum = "add0ab9360ddbd88cfeb3bd9574a1d85cfdfa14db10b3e21d3700dbc4328758f"
 
 [[package]]
 name = "httparse"
-version = "1.8.0"
+version = "1.9.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904"
+checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946"
 
 [[package]]
 name = "httpdate"
@@ -1017,53 +1006,39 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
 
 [[package]]
 name = "hyper"
-version = "0.14.27"
+version = "0.14.32"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468"
+checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7"
 dependencies = [
  "bytes",
  "futures-channel",
  "futures-core",
  "futures-util",
- "h2",
  "http",
  "http-body",
  "httparse",
  "httpdate",
  "itoa",
  "pin-project-lite",
- "socket2 0.4.9",
+ "socket2",
  "tokio",
  "tower-service",
  "tracing",
  "want",
 ]
 
-[[package]]
-name = "hyperlocal"
-version = "0.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0fafdf7b2b2de7c9784f76e02c0935e65a8117ec3b768644379983ab333ac98c"
-dependencies = [
- "futures-util",
- "hex",
- "hyper",
- "pin-project",
- "tokio",
-]
-
 [[package]]
 name = "iana-time-zone"
-version = "0.1.57"
+version = "0.1.61"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613"
+checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220"
 dependencies = [
  "android_system_properties",
  "core-foundation-sys",
  "iana-time-zone-haiku",
  "js-sys",
  "wasm-bindgen",
- "windows",
+ "windows-core",
 ]
 
 [[package]]
@@ -1075,22 +1050,6 @@ dependencies = [
  "cc",
 ]
 
-[[package]]
-name = "ident_case"
-version = "1.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
-
-[[package]]
-name = "idna"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c"
-dependencies = [
- "unicode-bidi",
- "unicode-normalization",
-]
-
 [[package]]
 name = "indexmap"
 version = "1.9.3"
@@ -1103,19 +1062,28 @@ dependencies = [
 
 [[package]]
 name = "indexmap"
-version = "2.0.0"
+version = "2.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d"
+checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f"
 dependencies = [
  "equivalent",
- "hashbrown 0.14.0",
+ "hashbrown 0.15.2",
+]
+
+[[package]]
+name = "inout"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5"
+dependencies = [
+ "generic-array",
 ]
 
 [[package]]
 name = "insta"
-version = "1.31.0"
+version = "1.41.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a0770b0a3d4c70567f0d58331f3088b0e4c4f56c9b8d764efe654b4a5d46de3a"
+checksum = "7e9ffc4d4892617c50a928c52b2961cb5174b6fc6ebf252b2fac9d21955c48b8"
 dependencies = [
  "console",
  "lazy_static",
@@ -1124,16 +1092,6 @@ dependencies = [
  "pest_derive",
  "serde",
  "similar",
- "yaml-rust",
-]
-
-[[package]]
-name = "instant"
-version = "0.1.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
-dependencies = [
- "cfg-if",
 ]
 
 [[package]]
@@ -1151,22 +1109,28 @@ version = "1.0.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2"
 dependencies = [
- "hermit-abi 0.3.2",
+ "hermit-abi 0.3.9",
  "libc",
  "windows-sys 0.48.0",
 ]
 
 [[package]]
 name = "is-terminal"
-version = "0.4.9"
+version = "0.4.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b"
+checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b"
 dependencies = [
- "hermit-abi 0.3.2",
- "rustix 0.38.11",
- "windows-sys 0.48.0",
+ "hermit-abi 0.4.0",
+ "libc",
+ "windows-sys 0.52.0",
 ]
 
+[[package]]
+name = "is_terminal_polyfill"
+version = "1.70.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
+
 [[package]]
 name = "itertools"
 version = "0.10.5"
@@ -1178,30 +1142,31 @@ dependencies = [
 
 [[package]]
 name = "itoa"
-version = "1.0.9"
+version = "1.0.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
+checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
 
 [[package]]
 name = "js-sys"
-version = "0.3.64"
+version = "0.3.76"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a"
+checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7"
 dependencies = [
+ "once_cell",
  "wasm-bindgen",
 ]
 
 [[package]]
 name = "lazy_static"
-version = "1.4.0"
+version = "1.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
 
 [[package]]
 name = "libc"
-version = "0.2.147"
+version = "0.2.169"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
+checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
 
 [[package]]
 name = "libffi"
@@ -1224,12 +1189,23 @@ dependencies = [
 
 [[package]]
 name = "libloading"
-version = "0.7.4"
+version = "0.8.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
+checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
 dependencies = [
  "cfg-if",
- "winapi",
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "libredox"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
+dependencies = [
+ "bitflags 2.6.0",
+ "libc",
+ "redox_syscall",
 ]
 
 [[package]]
@@ -1246,15 +1222,15 @@ checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519"
 
 [[package]]
 name = "linux-raw-sys"
-version = "0.4.5"
+version = "0.4.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503"
+checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
 
 [[package]]
 name = "lock_api"
-version = "0.4.10"
+version = "0.4.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16"
+checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
 dependencies = [
  "autocfg",
  "scopeguard",
@@ -1262,9 +1238,9 @@ dependencies = [
 
 [[package]]
 name = "log"
-version = "0.4.20"
+version = "0.4.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
+checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
 
 [[package]]
 name = "maplit"
@@ -1272,6 +1248,15 @@ version = "1.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
 
+[[package]]
+name = "matchers"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558"
+dependencies = [
+ "regex-automata 0.1.10",
+]
+
 [[package]]
 name = "matchit"
 version = "0.5.0"
@@ -1288,7 +1273,7 @@ dependencies = [
  "chrono",
  "clap 4.3.24",
  "clap_complete",
- "env_logger 0.10.0",
+ "env_logger 0.10.2",
  "handlebars",
  "log",
  "memchr",
@@ -1324,7 +1309,7 @@ dependencies = [
  "serde",
  "serde_json",
  "tempfile",
- "ts-rs",
+ "ts-rs 6.2.1",
  "wait-timeout",
 ]
 
@@ -1337,12 +1322,12 @@ dependencies = [
  "anyhow",
  "chrono",
  "clap 4.3.24",
- "env_logger 0.10.0",
+ "env_logger 0.10.2",
  "html-escape",
  "log",
  "mdbook",
  "rayon",
- "semver",
+ "semver 1.0.20",
  "serde",
  "serde_json",
  "tempfile",
@@ -1350,9 +1335,9 @@ dependencies = [
 
 [[package]]
 name = "measureme"
-version = "10.1.1"
+version = "11.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1930d162935fecd56fc4e0f6729eb3483bac1264542eb4ea31570b86a434b6bc"
+checksum = "dfa4a40f09af7aa6faef38285402a78847d0d72bf8827006cd2a332e1e6e4a8d"
 dependencies = [
  "log",
  "memmap2",
@@ -1364,9 +1349,9 @@ dependencies = [
 
 [[package]]
 name = "memchr"
-version = "2.6.2"
+version = "2.7.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5486aed0026218e61b8a01d5fbd5a0a134649abb71a0e53b7bc088529dced86e"
+checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
 
 [[package]]
 name = "memmap2"
@@ -1377,15 +1362,6 @@ dependencies = [
  "libc",
 ]
 
-[[package]]
-name = "memoffset"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c"
-dependencies = [
- "autocfg",
-]
-
 [[package]]
 name = "mime"
 version = "0.3.17"
@@ -1400,50 +1376,42 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
 
 [[package]]
 name = "miniz_oxide"
-version = "0.7.1"
+version = "0.8.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
+checksum = "4ffbe83022cedc1d264172192511ae958937694cd57ce297164951b8b3568394"
 dependencies = [
- "adler",
+ "adler2",
 ]
 
 [[package]]
 name = "mio"
-version = "0.8.8"
+version = "1.0.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2"
+checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd"
 dependencies = [
  "libc",
  "wasi",
- "windows-sys 0.48.0",
+ "windows-sys 0.52.0",
 ]
 
 [[package]]
 name = "miri"
 version = "0.1.0"
-source = "git+https://github.com/rust-lang/miri.git?rev=63c5542edf907dd797db82c4c2979e3c4df71a8b#63c5542edf907dd797db82c4c2979e3c4df71a8b"
+source = "git+https://github.com/rust-lang/miri?rev=afdbb080fe4b8e73838fffdbea8b290aa246f3d7#afdbb080fe4b8e73838fffdbea8b290aa246f3d7"
 dependencies = [
- "ctrlc",
- "env_logger 0.9.3",
+ "aes",
+ "chrono",
+ "chrono-tz",
+ "directories",
  "getrandom",
  "libc",
  "libffi",
  "libloading",
- "log",
  "measureme",
  "rand",
  "smallvec",
-]
-
-[[package]]
-name = "nix"
-version = "0.27.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053"
-dependencies = [
- "bitflags 2.4.0",
- "cfg-if",
- "libc",
+ "tikv-jemalloc-sys",
+ "windows-sys 0.52.0",
 ]
 
 [[package]]
@@ -1468,38 +1436,38 @@ dependencies = [
 ]
 
 [[package]]
-name = "num-traits"
-version = "0.2.16"
+name = "nu-ansi-term"
+version = "0.46.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2"
+checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84"
 dependencies = [
- "autocfg",
+ "overload",
+ "winapi",
 ]
 
 [[package]]
-name = "num_cpus"
-version = "1.16.0"
+name = "num-traits"
+version = "0.2.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
+checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
 dependencies = [
- "hermit-abi 0.3.2",
- "libc",
+ "autocfg",
 ]
 
 [[package]]
 name = "object"
-version = "0.32.0"
+version = "0.36.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "77ac5bbd07aea88c60a577a1ce218075ffd59208b2d7ca97adf9bfc5aeb21ebe"
+checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87"
 dependencies = [
  "memchr",
 ]
 
 [[package]]
 name = "once_cell"
-version = "1.18.0"
+version = "1.20.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
+checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
 
 [[package]]
 name = "opener"
@@ -1511,42 +1479,61 @@ dependencies = [
  "winapi",
 ]
 
+[[package]]
+name = "option-ext"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
+
 [[package]]
 name = "os_str_bytes"
-version = "6.5.1"
+version = "6.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1"
+
+[[package]]
+name = "overload"
+version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4d5d9eb14b174ee9aa2ef96dc2b94637a2d4b6e7cb873c7e171f0c20c6cf3eac"
+checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
 
 [[package]]
 name = "parking_lot"
-version = "0.11.2"
+version = "0.12.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
+checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
 dependencies = [
- "instant",
  "lock_api",
  "parking_lot_core",
 ]
 
 [[package]]
 name = "parking_lot_core"
-version = "0.8.6"
+version = "0.9.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc"
+checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
 dependencies = [
  "cfg-if",
- "instant",
  "libc",
- "redox_syscall 0.2.16",
+ "redox_syscall",
  "smallvec",
- "winapi",
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "parse-zoneinfo"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1f2a05b18d44e2957b88f96ba460715e295bc1d7510468a2f3d3b44535d26c24"
+dependencies = [
+ "regex",
 ]
 
 [[package]]
 name = "percent-encoding"
-version = "2.3.0"
+version = "2.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94"
+checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
 
 [[package]]
 name = "perf-event-open-sys"
@@ -1559,20 +1546,20 @@ dependencies = [
 
 [[package]]
 name = "pest"
-version = "2.7.3"
+version = "2.7.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d7a4d085fd991ac8d5b05a147b437791b4260b76326baf0fc60cf7c9c27ecd33"
+checksum = "8b7cafe60d6cf8e62e1b9b2ea516a089c008945bb5a275416789e7db0bc199dc"
 dependencies = [
  "memchr",
- "thiserror",
+ "thiserror 2.0.9",
  "ucd-trie",
 ]
 
 [[package]]
 name = "pest_derive"
-version = "2.7.3"
+version = "2.7.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a2bee7be22ce7918f641a33f08e3f43388c7656772244e2bbb2477f44cc9021a"
+checksum = "816518421cfc6887a0d62bf441b6ffb4536fcc926395a69e1a85852d4363f57e"
 dependencies = [
  "pest",
  "pest_generator",
@@ -1580,53 +1567,91 @@ dependencies = [
 
 [[package]]
 name = "pest_generator"
-version = "2.7.3"
+version = "2.7.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d1511785c5e98d79a05e8a6bc34b4ac2168a0e3e92161862030ad84daa223141"
+checksum = "7d1396fd3a870fc7838768d171b4616d5c91f6cc25e377b673d714567d99377b"
 dependencies = [
  "pest",
  "pest_meta",
  "proc-macro2",
  "quote",
- "syn 2.0.29",
+ "syn 2.0.93",
 ]
 
 [[package]]
 name = "pest_meta"
-version = "2.7.3"
+version = "2.7.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b42f0394d3123e33353ca5e1e89092e533d2cc490389f2bd6131c43c634ebc5f"
+checksum = "e1e58089ea25d717bfd31fb534e4f3afcc2cc569c70de3e239778991ea3b7dea"
 dependencies = [
  "once_cell",
  "pest",
  "sha2",
 ]
 
+[[package]]
+name = "phf"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc"
+dependencies = [
+ "phf_shared",
+]
+
+[[package]]
+name = "phf_codegen"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e8d39688d359e6b34654d328e262234662d16cc0f60ec8dcbe5e718709342a5a"
+dependencies = [
+ "phf_generator",
+ "phf_shared",
+]
+
+[[package]]
+name = "phf_generator"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0"
+dependencies = [
+ "phf_shared",
+ "rand",
+]
+
+[[package]]
+name = "phf_shared"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b"
+dependencies = [
+ "siphasher",
+]
+
 [[package]]
 name = "pin-project"
-version = "1.1.3"
+version = "1.1.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422"
+checksum = "be57f64e946e500c8ee36ef6331845d40a93055567ec57e8fae13efd33759b95"
 dependencies = [
  "pin-project-internal",
 ]
 
 [[package]]
 name = "pin-project-internal"
-version = "1.1.3"
+version = "1.1.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405"
+checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.29",
+ "syn 2.0.93",
 ]
 
 [[package]]
 name = "pin-project-lite"
-version = "0.2.13"
+version = "0.2.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
+checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff"
 
 [[package]]
 name = "pin-utils"
@@ -1636,9 +1661,12 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
 
 [[package]]
 name = "ppv-lite86"
-version = "0.2.17"
+version = "0.2.20"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
+checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
+dependencies = [
+ "zerocopy",
+]
 
 [[package]]
 name = "proc-macro-error"
@@ -1666,29 +1694,29 @@ dependencies = [
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.66"
+version = "1.0.92"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9"
+checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
 dependencies = [
  "unicode-ident",
 ]
 
 [[package]]
 name = "pulldown-cmark"
-version = "0.9.3"
+version = "0.9.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "77a1a2f1f0a7ecff9c31abbe177637be0e97a0aef46cf8738ece09327985d998"
+checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b"
 dependencies = [
- "bitflags 1.3.2",
+ "bitflags 2.6.0",
  "memchr",
  "unicase",
 ]
 
 [[package]]
 name = "quote"
-version = "1.0.33"
+version = "1.0.38"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
+checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc"
 dependencies = [
  "proc-macro2",
 ]
@@ -1725,9 +1753,9 @@ dependencies = [
 
 [[package]]
 name = "rayon"
-version = "1.7.0"
+version = "1.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b"
+checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
 dependencies = [
  "either",
  "rayon-core",
@@ -1735,68 +1763,83 @@ dependencies = [
 
 [[package]]
 name = "rayon-core"
-version = "1.11.0"
+version = "1.12.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d"
+checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
 dependencies = [
- "crossbeam-channel",
  "crossbeam-deque",
  "crossbeam-utils",
- "num_cpus",
 ]
 
 [[package]]
 name = "redox_syscall"
-version = "0.2.16"
+version = "0.5.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
+checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834"
 dependencies = [
- "bitflags 1.3.2",
+ "bitflags 2.6.0",
 ]
 
 [[package]]
-name = "redox_syscall"
-version = "0.3.5"
+name = "redox_users"
+version = "0.4.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
+checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
 dependencies = [
- "bitflags 1.3.2",
+ "getrandom",
+ "libredox",
+ "thiserror 1.0.69",
 ]
 
 [[package]]
 name = "regex"
-version = "1.9.4"
+version = "1.11.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "12de2eff854e5fa4b1295edd650e227e9d8fb0c9e90b12e7f36d6a6811791a29"
+checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
 dependencies = [
  "aho-corasick",
  "memchr",
- "regex-automata",
- "regex-syntax",
+ "regex-automata 0.4.9",
+ "regex-syntax 0.8.5",
 ]
 
 [[package]]
 name = "regex-automata"
-version = "0.3.7"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
+dependencies = [
+ "regex-syntax 0.6.29",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.4.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49530408a136e16e5b486e883fbb6ba058e8e4e8ae6621a77b048b314336e629"
+checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
 dependencies = [
  "aho-corasick",
  "memchr",
- "regex-syntax",
+ "regex-syntax 0.8.5",
 ]
 
 [[package]]
 name = "regex-syntax"
-version = "0.7.5"
+version = "0.6.29"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
+
+[[package]]
+name = "regex-syntax"
+version = "0.8.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da"
+checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
 
 [[package]]
 name = "rustc-demangle"
-version = "0.1.23"
+version = "0.1.24"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
+checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
 
 [[package]]
 name = "rustc-hash"
@@ -1806,15 +1849,16 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
 
 [[package]]
 name = "rustc_plugin"
-version = "0.7.0-nightly-2023-08-25"
-source = "git+https://github.com/cognitive-engineering-lab/rustc_plugin?rev=d4b3c43b0695d42030f9cb3a62fc27cc337019d1#d4b3c43b0695d42030f9cb3a62fc27cc337019d1"
+version = "0.12.0-nightly-2024-12-15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "351d0edb6bb7f15aa21d83c29604cdc3bdcec506e12233868b369ee6d3328da3"
 dependencies = [
  "cargo_metadata",
  "log",
  "rustc_tools_util",
  "serde",
  "serde_json",
- "toml 0.7.6",
+ "toml 0.7.8",
 ]
 
 [[package]]
@@ -1825,8 +1869,9 @@ checksum = "b3c5a95edfa0c893236ae4778bb7c4752760e4c0d245e19b5eff33c5aa5eb9dc"
 
 [[package]]
 name = "rustc_utils"
-version = "0.7.0-nightly-2023-08-25"
-source = "git+https://github.com/cognitive-engineering-lab/rustc_plugin?rev=d4b3c43b0695d42030f9cb3a62fc27cc337019d1#d4b3c43b0695d42030f9cb3a62fc27cc337019d1"
+version = "0.12.0-nightly-2024-12-15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a82a375e5df4530b4c5e94ab8251c754c92c3e593efaf8214e572ea422bf3a0"
 dependencies = [
  "anyhow",
  "cfg-if",
@@ -1835,14 +1880,23 @@ dependencies = [
  "regex",
  "serde",
  "textwrap",
- "ts-rs",
+ "ts-rs 7.1.1",
+]
+
+[[package]]
+name = "rustc_version"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c5f5376ea5e30ce23c03eb77cbe4962b988deead10910c372b226388b594c084"
+dependencies = [
+ "semver 0.1.20",
 ]
 
 [[package]]
 name = "rustix"
-version = "0.37.23"
+version = "0.37.27"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06"
+checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2"
 dependencies = [
  "bitflags 1.3.2",
  "errno",
@@ -1854,22 +1908,22 @@ dependencies = [
 
 [[package]]
 name = "rustix"
-version = "0.38.11"
+version = "0.38.42"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c0c3dde1fc030af041adc40e79c0e7fbcf431dd24870053d187d7c66e4b87453"
+checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85"
 dependencies = [
- "bitflags 2.4.0",
+ "bitflags 2.6.0",
  "errno",
  "libc",
- "linux-raw-sys 0.4.5",
- "windows-sys 0.48.0",
+ "linux-raw-sys 0.4.14",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
 name = "ryu"
-version = "1.0.15"
+version = "1.0.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
+checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
 
 [[package]]
 name = "scopeguard"
@@ -1879,9 +1933,15 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
 
 [[package]]
 name = "semver"
-version = "1.0.18"
+version = "0.1.20"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918"
+checksum = "d4f410fedcf71af0345d7607d246e7ad15faaadd49d240ee3b24e5dc21a820ac"
+
+[[package]]
+name = "semver"
+version = "1.0.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090"
 dependencies = [
  "serde",
 ]
@@ -1919,9 +1979,9 @@ dependencies = [
 
 [[package]]
 name = "serde_spanned"
-version = "0.6.3"
+version = "0.6.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186"
+checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1"
 dependencies = [
  "serde",
 ]
@@ -1939,58 +1999,51 @@ dependencies = [
 ]
 
 [[package]]
-name = "serde_with"
-version = "1.14.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "678b5a069e50bf00ecd22d0cd8ddf7c236f68581b03db652061ed5eb13a312ff"
-dependencies = [
- "serde",
- "serde_with_macros",
-]
-
-[[package]]
-name = "serde_with_macros"
-version = "1.5.2"
+name = "sha2"
+version = "0.10.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082"
+checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
 dependencies = [
- "darling",
- "proc-macro2",
- "quote",
- "syn 1.0.109",
+ "cfg-if",
+ "cpufeatures",
+ "digest",
 ]
 
 [[package]]
-name = "sha2"
-version = "0.10.7"
+name = "sharded-slab"
+version = "0.1.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8"
+checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
 dependencies = [
- "cfg-if",
- "cpufeatures",
- "digest",
+ "lazy_static",
 ]
 
 [[package]]
 name = "shlex"
-version = "1.1.0"
+version = "1.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3"
+checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
 
 [[package]]
 name = "signal-hook-registry"
-version = "1.4.1"
+version = "1.4.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1"
+checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1"
 dependencies = [
  "libc",
 ]
 
 [[package]]
 name = "similar"
-version = "2.2.1"
+version = "2.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1de1d4f81173b03af4c0cbed3c898f6bff5b870e4a7f5d6f4057d62a7a4b686e"
+
+[[package]]
+name = "siphasher"
+version = "0.3.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "420acb44afdae038210c99e69aae24109f32f15500aa708e81d46c9f29d55fcf"
+checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d"
 
 [[package]]
 name = "slab"
@@ -2001,17 +2054,23 @@ dependencies = [
  "autocfg",
 ]
 
+[[package]]
+name = "sliding_windows"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a830e5d74dce35884bac85ecdc68c1ae96b9451918cc484f39340049c7a55f5e"
+
 [[package]]
 name = "smallvec"
-version = "1.11.0"
+version = "1.13.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9"
+checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
 
 [[package]]
 name = "smawk"
-version = "0.3.1"
+version = "0.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f67ad224767faa3c7d8b6d91985b78e70a1324408abcb1cfcc2be4c06bc06043"
+checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c"
 
 [[package]]
 name = "snafu"
@@ -2037,22 +2096,12 @@ dependencies = [
 
 [[package]]
 name = "socket2"
-version = "0.4.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662"
-dependencies = [
- "libc",
- "winapi",
-]
-
-[[package]]
-name = "socket2"
-version = "0.5.3"
+version = "0.5.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2538b18701741680e0322a2302176d3253a35388e2e62f172f64f4f16605f877"
+checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8"
 dependencies = [
  "libc",
- "windows-sys 0.48.0",
+ "windows-sys 0.52.0",
 ]
 
 [[package]]
@@ -2074,9 +2123,9 @@ dependencies = [
 
 [[package]]
 name = "syn"
-version = "2.0.29"
+version = "2.0.93"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a"
+checksum = "9c786062daee0d6db1132800e623df74274a0a87322d8e183338e01b3d98d058"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -2091,9 +2140,9 @@ checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
 
 [[package]]
 name = "tar"
-version = "0.4.40"
+version = "0.4.43"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b16afcea1f22891c49a00c751c7b63b2233284064f11a200fc624137c51e2ddb"
+checksum = "c65998313f8e17d0d553d28f91a0df93e4dbbbf770279c7bc21ca0f09ea1a1f6"
 dependencies = [
  "filetime",
  "libc",
@@ -2102,22 +2151,22 @@ dependencies = [
 
 [[package]]
 name = "tempfile"
-version = "3.8.0"
+version = "3.14.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef"
+checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c"
 dependencies = [
  "cfg-if",
  "fastrand",
- "redox_syscall 0.3.5",
- "rustix 0.38.11",
- "windows-sys 0.48.0",
+ "once_cell",
+ "rustix 0.38.42",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
 name = "termcolor"
-version = "1.2.0"
+version = "1.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6"
+checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
 dependencies = [
  "winapi-util",
 ]
@@ -2128,26 +2177,37 @@ version = "0.2.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8e6bf6f19e9f8ed8d4048dc22981458ebcf406d67e94cd422e5ecd73d63b3237"
 dependencies = [
- "rustix 0.37.23",
+ "rustix 0.37.27",
  "windows-sys 0.48.0",
 ]
 
 [[package]]
 name = "test-log"
-version = "0.2.12"
+version = "0.2.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3dffced63c2b5c7be278154d76b479f9f9920ed34e7574201407f0b14e2bbb93"
+dependencies = [
+ "env_logger 0.11.6",
+ "test-log-macros",
+ "tracing-subscriber",
+]
+
+[[package]]
+name = "test-log-macros"
+version = "0.2.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d9601d162c1d77e62c1ea0bc8116cd1caf143ce3af947536c3c9052a1677fe0c"
+checksum = "5999e24eaa32083191ba4e425deb75cdf25efefabe5aaccb7446dd0d4122a3f5"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 1.0.109",
+ "syn 2.0.93",
 ]
 
 [[package]]
 name = "textwrap"
-version = "0.16.0"
+version = "0.16.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d"
+checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9"
 dependencies = [
  "smawk",
  "unicode-linebreak",
@@ -2156,80 +2216,90 @@ dependencies = [
 
 [[package]]
 name = "thiserror"
-version = "1.0.47"
+version = "1.0.69"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
+dependencies = [
+ "thiserror-impl 1.0.69",
+]
+
+[[package]]
+name = "thiserror"
+version = "2.0.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "97a802ec30afc17eee47b2855fc72e0c4cd62be9b4efe6591edde0ec5bd68d8f"
+checksum = "f072643fd0190df67a8bab670c20ef5d8737177d6ac6b2e9a236cb096206b2cc"
 dependencies = [
- "thiserror-impl",
+ "thiserror-impl 2.0.9",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "1.0.47"
+version = "1.0.69"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6bb623b56e39ab7dcd4b1b98bb6c8f8d907ed255b18de254088016b27a8ee19b"
+checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.29",
+ "syn 2.0.93",
 ]
 
 [[package]]
-name = "tinyvec"
-version = "1.6.0"
+name = "thiserror-impl"
+version = "2.0.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
+checksum = "7b50fa271071aae2e6ee85f842e2e28ba8cd2c5fb67f11fcb1fd70b276f9e7d4"
 dependencies = [
- "tinyvec_macros",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.93",
 ]
 
 [[package]]
-name = "tinyvec_macros"
-version = "0.1.1"
+name = "thread_local"
+version = "1.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c"
+dependencies = [
+ "cfg-if",
+ "once_cell",
+]
+
+[[package]]
+name = "tikv-jemalloc-sys"
+version = "0.6.0+5.3.0-1-ge13ca993e8ccb9ba9847cc330696e02839f328f7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
+checksum = "cd3c60906412afa9c2b5b5a48ca6a5abe5736aec9eb48ad05037a677e52e4e2d"
+dependencies = [
+ "cc",
+ "libc",
+]
 
 [[package]]
 name = "tokio"
-version = "1.32.0"
+version = "1.42.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "17ed6077ed6cd6c74735e21f37eb16dc3935f96878b1fe961074089cc80893f9"
+checksum = "5cec9b21b0450273377fc97bd4c33a8acffc8c996c987a7c5b319a0083707551"
 dependencies = [
  "backtrace",
  "bytes",
  "libc",
  "mio",
- "num_cpus",
  "pin-project-lite",
  "signal-hook-registry",
- "socket2 0.5.3",
+ "socket2",
  "tokio-macros",
- "windows-sys 0.48.0",
+ "windows-sys 0.52.0",
 ]
 
 [[package]]
 name = "tokio-macros"
-version = "2.1.0"
+version = "2.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e"
+checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.29",
-]
-
-[[package]]
-name = "tokio-util"
-version = "0.7.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d"
-dependencies = [
- "bytes",
- "futures-core",
- "futures-sink",
- "pin-project-lite",
- "tokio",
- "tracing",
+ "syn 2.0.93",
 ]
 
 [[package]]
@@ -2243,9 +2313,9 @@ dependencies = [
 
 [[package]]
 name = "toml"
-version = "0.7.6"
+version = "0.7.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c17e963a819c331dcacd7ab957d80bc2b9a9c1e71c804826d2f283dd65306542"
+checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257"
 dependencies = [
  "serde",
  "serde_spanned",
@@ -2255,20 +2325,20 @@ dependencies = [
 
 [[package]]
 name = "toml_datetime"
-version = "0.6.3"
+version = "0.6.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b"
+checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41"
 dependencies = [
  "serde",
 ]
 
 [[package]]
 name = "toml_edit"
-version = "0.19.14"
+version = "0.19.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a"
+checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421"
 dependencies = [
- "indexmap 2.0.0",
+ "indexmap 2.7.0",
  "serde",
  "serde_spanned",
  "toml_datetime",
@@ -2319,23 +2389,22 @@ dependencies = [
 
 [[package]]
 name = "tower-layer"
-version = "0.3.2"
+version = "0.3.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0"
+checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e"
 
 [[package]]
 name = "tower-service"
-version = "0.3.2"
+version = "0.3.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52"
+checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
 
 [[package]]
 name = "tracing"
-version = "0.1.37"
+version = "0.1.41"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
+checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
 dependencies = [
- "cfg-if",
  "log",
  "pin-project-lite",
  "tracing-core",
@@ -2343,18 +2412,47 @@ dependencies = [
 
 [[package]]
 name = "tracing-core"
-version = "0.1.31"
+version = "0.1.33"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c"
+dependencies = [
+ "once_cell",
+ "valuable",
+]
+
+[[package]]
+name = "tracing-log"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
+dependencies = [
+ "log",
+ "once_cell",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-subscriber"
+version = "0.3.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a"
+checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008"
 dependencies = [
+ "matchers",
+ "nu-ansi-term",
  "once_cell",
+ "regex",
+ "sharded-slab",
+ "thread_local",
+ "tracing",
+ "tracing-core",
+ "tracing-log",
 ]
 
 [[package]]
 name = "try-lock"
-version = "0.2.4"
+version = "0.2.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed"
+checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
 
 [[package]]
 name = "ts-rs"
@@ -2362,8 +2460,18 @@ version = "6.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "4added4070a4fdf9df03457206cd2e4b12417c8560a2954d91ffcbe60177a56a"
 dependencies = [
- "thiserror",
- "ts-rs-macros",
+ "thiserror 1.0.69",
+ "ts-rs-macros 6.2.0",
+]
+
+[[package]]
+name = "ts-rs"
+version = "7.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc2cae1fc5d05d47aa24b64f9a4f7cba24cdc9187a2084dd97ac57bef5eccae6"
+dependencies = [
+ "thiserror 1.0.69",
+ "ts-rs-macros 7.1.1",
 ]
 
 [[package]]
@@ -2380,37 +2488,41 @@ dependencies = [
 ]
 
 [[package]]
-name = "typenum"
-version = "1.16.0"
+name = "ts-rs-macros"
+version = "7.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
+checksum = "73f7f9b821696963053a89a7bd8b292dc34420aea8294d7b225274d488f3ec92"
+dependencies = [
+ "Inflector",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.93",
+ "termcolor",
+]
 
 [[package]]
-name = "ucd-trie"
-version = "0.1.6"
+name = "typenum"
+version = "1.17.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9"
+checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
 
 [[package]]
-name = "unicase"
-version = "2.7.0"
+name = "ucd-trie"
+version = "0.1.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89"
-dependencies = [
- "version_check",
-]
+checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971"
 
 [[package]]
-name = "unicode-bidi"
-version = "0.3.13"
+name = "unicase"
+version = "2.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460"
+checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539"
 
 [[package]]
 name = "unicode-ident"
-version = "1.0.11"
+version = "1.0.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c"
+checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
 
 [[package]]
 name = "unicode-linebreak"
@@ -2418,49 +2530,35 @@ version = "0.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f"
 
-[[package]]
-name = "unicode-normalization"
-version = "0.1.22"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921"
-dependencies = [
- "tinyvec",
-]
-
 [[package]]
 name = "unicode-width"
-version = "0.1.10"
+version = "0.1.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
+checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
 
 [[package]]
-name = "url"
-version = "2.4.1"
+name = "utf8-width"
+version = "0.1.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5"
-dependencies = [
- "form_urlencoded",
- "idna",
- "percent-encoding",
-]
+checksum = "86bd8d4e895da8537e5315b8254664e6b769c4ff3db18321b297a1e7004392e3"
 
 [[package]]
-name = "utf8-width"
-version = "0.1.6"
+name = "utf8parse"
+version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5190c9442dcdaf0ddd50f37420417d219ae5261bbf5db120d0f9bab996c9cba1"
+checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
 
 [[package]]
-name = "utf8parse"
-version = "0.2.1"
+name = "valuable"
+version = "0.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
+checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
 
 [[package]]
 name = "version_check"
-version = "0.9.4"
+version = "0.9.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
+checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
 
 [[package]]
 name = "wait-timeout"
@@ -2488,34 +2586,34 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
 
 [[package]]
 name = "wasm-bindgen"
-version = "0.2.87"
+version = "0.2.99"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342"
+checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396"
 dependencies = [
  "cfg-if",
+ "once_cell",
  "wasm-bindgen-macro",
 ]
 
 [[package]]
 name = "wasm-bindgen-backend"
-version = "0.2.87"
+version = "0.2.99"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd"
+checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79"
 dependencies = [
  "bumpalo",
  "log",
- "once_cell",
  "proc-macro2",
  "quote",
- "syn 2.0.29",
+ "syn 2.0.93",
  "wasm-bindgen-shared",
 ]
 
 [[package]]
 name = "wasm-bindgen-macro"
-version = "0.2.87"
+version = "0.2.99"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d"
+checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe"
 dependencies = [
  "quote",
  "wasm-bindgen-macro-support",
@@ -2523,22 +2621,22 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro-support"
-version = "0.2.87"
+version = "0.2.99"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
+checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.29",
+ "syn 2.0.93",
  "wasm-bindgen-backend",
  "wasm-bindgen-shared",
 ]
 
 [[package]]
 name = "wasm-bindgen-shared"
-version = "0.2.87"
+version = "0.2.99"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1"
+checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6"
 
 [[package]]
 name = "winapi"
@@ -2558,11 +2656,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
 
 [[package]]
 name = "winapi-util"
-version = "0.1.5"
+version = "0.1.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
+checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
 dependencies = [
- "winapi",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
@@ -2572,45 +2670,39 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
 
 [[package]]
-name = "windows"
-version = "0.48.0"
+name = "windows-core"
+version = "0.52.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f"
+checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
 dependencies = [
- "windows-targets 0.48.5",
+ "windows-targets 0.52.6",
 ]
 
 [[package]]
 name = "windows-sys"
-version = "0.45.0"
+version = "0.48.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
+checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
 dependencies = [
- "windows-targets 0.42.2",
+ "windows-targets 0.48.5",
 ]
 
 [[package]]
 name = "windows-sys"
-version = "0.48.0"
+version = "0.52.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
+checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
 dependencies = [
- "windows-targets 0.48.5",
+ "windows-targets 0.52.6",
 ]
 
 [[package]]
-name = "windows-targets"
-version = "0.42.2"
+name = "windows-sys"
+version = "0.59.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
+checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
 dependencies = [
- "windows_aarch64_gnullvm 0.42.2",
- "windows_aarch64_msvc 0.42.2",
- "windows_i686_gnu 0.42.2",
- "windows_i686_msvc 0.42.2",
- "windows_x86_64_gnu 0.42.2",
- "windows_x86_64_gnullvm 0.42.2",
- "windows_x86_64_msvc 0.42.2",
+ "windows-targets 0.52.6",
 ]
 
 [[package]]
@@ -2644,12 +2736,6 @@ dependencies = [
  "windows_x86_64_msvc 0.52.6",
 ]
 
-[[package]]
-name = "windows_aarch64_gnullvm"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
-
 [[package]]
 name = "windows_aarch64_gnullvm"
 version = "0.48.5"
@@ -2662,12 +2748,6 @@ version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
 
-[[package]]
-name = "windows_aarch64_msvc"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
-
 [[package]]
 name = "windows_aarch64_msvc"
 version = "0.48.5"
@@ -2680,12 +2760,6 @@ version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
 
-[[package]]
-name = "windows_i686_gnu"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
-
 [[package]]
 name = "windows_i686_gnu"
 version = "0.48.5"
@@ -2704,12 +2778,6 @@ version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
 
-[[package]]
-name = "windows_i686_msvc"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
-
 [[package]]
 name = "windows_i686_msvc"
 version = "0.48.5"
@@ -2722,12 +2790,6 @@ version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
 
-[[package]]
-name = "windows_x86_64_gnu"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
-
 [[package]]
 name = "windows_x86_64_gnu"
 version = "0.48.5"
@@ -2740,12 +2802,6 @@ version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
 
-[[package]]
-name = "windows_x86_64_gnullvm"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
-
 [[package]]
 name = "windows_x86_64_gnullvm"
 version = "0.48.5"
@@ -2758,12 +2814,6 @@ version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
 
-[[package]]
-name = "windows_x86_64_msvc"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
-
 [[package]]
 name = "windows_x86_64_msvc"
 version = "0.48.5"
@@ -2778,27 +2828,41 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
 
 [[package]]
 name = "winnow"
-version = "0.5.15"
+version = "0.5.40"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7c2e3184b9c4e92ad5167ca73039d0c42476302ab603e2fec4487511f38ccefc"
+checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876"
 dependencies = [
  "memchr",
 ]
 
 [[package]]
 name = "xattr"
-version = "1.0.1"
+version = "1.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f4686009f71ff3e5c4dbcf1a282d0a44db3f021ba69350cd42086b3e5f1c6985"
+checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f"
 dependencies = [
  "libc",
+ "linux-raw-sys 0.4.14",
+ "rustix 0.38.42",
 ]
 
 [[package]]
-name = "yaml-rust"
-version = "0.4.5"
+name = "zerocopy"
+version = "0.7.35"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
+checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
 dependencies = [
- "linked-hash-map",
+ "byteorder",
+ "zerocopy-derive",
+]
+
+[[package]]
+name = "zerocopy-derive"
+version = "0.7.35"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.93",
 ]
diff --git a/Cargo.toml b/Cargo.toml
index c593e615f..635d37b07 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -4,7 +4,10 @@ exclude = [ "files" ]
 resolver = "2"
 
 [workspace.dependencies]
+anyhow = "1.0.0"
 serde = { version = "=1.0.149", features = ["derive"] }
+rustc_plugin = "=0.12.0-nightly-2024-12-15"
+rustc_utils = "=0.12.0-nightly-2024-12-15"
 
 # Make snapshot testing faster
 [profile.dev.package.insta]
@@ -12,7 +15,3 @@ opt-level = 3
 
 [profile.dev.package.similar]
 opt-level = 3
-
-[patch.crates-io]
-rustc_plugin = { git = "https://github.com/cognitive-engineering-lab/rustc_plugin", rev = "d4b3c43b0695d42030f9cb3a62fc27cc337019d1" }
-rustc_utils = { git = "https://github.com/cognitive-engineering-lab/rustc_plugin", rev = "d4b3c43b0695d42030f9cb3a62fc27cc337019d1" }
diff --git a/Dockerfile b/Dockerfile
deleted file mode 100644
index 9fe32fffd..000000000
--- a/Dockerfile
+++ /dev/null
@@ -1,29 +0,0 @@
-FROM rustlang/rust:nightly-alpine
-ENV CARGO_UNSTABLE_SPARSE_REGISTRY=true
-
-RUN rustup set profile minimal                                  && \
-    rustup default nightly-2023-08-25-x86_64-unknown-linux-musl && \
-    rustup toolchain uninstall nightly                          && \
-    rustup toolchain uninstall stable                           && \
-    rustup component add --toolchain nightly-2023-08-25            \
-                         --target x86_64-unknown-linux-musl        \
-                         rust-src rustc-dev llvm-tools-preview miri
-
-RUN apk add --no-cache build-base musl-dev libc-dev linux-headers
-
-WORKDIR /aquascope
-
-COPY Cargo.toml Cargo.lock rust-toolchain.toml ./
-COPY crates ./crates
-
-ENV TARGET_CC=x86_64-linux-musl-gcc
-ENV RUSTFLAGS="-C target-feature=-crt-static"
-
-RUN cargo miri setup
-ENV MIRI_SYSROOT=/root/.cache/miri
-
-RUN cargo install --path crates/aquascope_front --target x86_64-unknown-linux-musl --locked
-RUN cargo clean
-RUN rm -rf /aquascope
-
-WORKDIR /app
diff --git a/Makefile.toml b/Makefile.toml
index 37661d323..1a11bc911 100644
--- a/Makefile.toml
+++ b/Makefile.toml
@@ -41,7 +41,7 @@ script = "cargo install --path crates/mdbook-aquascope --locked"
 [tasks.playground-front]
 script = """
 export MIRI_SYSROOT=$(cargo miri setup --print-sysroot)
-cd frontend && depot build -w
+cd frontend && depot --no-fullscreen build --watch
 """
 
 [tasks.playground.run_task]
diff --git a/crates/aquascope/Cargo.toml b/crates/aquascope/Cargo.toml
index d983ab8ed..df9fdcf70 100644
--- a/crates/aquascope/Cargo.toml
+++ b/crates/aquascope/Cargo.toml
@@ -18,17 +18,18 @@ rustc_private = true
 testing = []
 
 [dependencies]
-anyhow = "1.0.0"
+anyhow.workspace = true
 log = "0.4"
 itertools = "0.10.5"
-serde = { workspace = true }
-ts-rs = "6.2"
+serde.workspace = true
+ts-rs = "7"
 regex = "1"
 fluid-let = "1.0"
-rustc_utils = {version = "0.7.0-nightly-2023-08-25", features = ["graphviz", "ts-rs", "serde", "test"]}
+fuzzy_match = "0.2.1"
+rustc_utils = {workspace = true, features = ["graphviz", "ts-rs", "serde", "test"]}
 
 # interpret module
-miri = {git = "https://github.com/rust-lang/miri.git", rev = "63c5542edf907dd797db82c4c2979e3c4df71a8b"}
+miri = {git = "https://github.com/rust-lang/miri", rev = "afdbb080fe4b8e73838fffdbea8b290aa246f3d7"}
 aquascope_workspace_utils = { version = "0.3", path = "../aquascope_workspace_utils" }
 
 # testing utils
diff --git a/crates/aquascope/src/analysis/boundaries/mod.rs b/crates/aquascope/src/analysis/boundaries/mod.rs
index 5bb595837..57fa1a285 100644
--- a/crates/aquascope/src/analysis/boundaries/mod.rs
+++ b/crates/aquascope/src/analysis/boundaries/mod.rs
@@ -180,7 +180,10 @@ use either::Either;
 use path_visitor::get_path_boundaries;
 use rustc_hir::HirId;
 use rustc_middle::{
-  mir::{Body, Location, Mutability, Place, Rvalue, Statement, StatementKind},
+  mir::{
+    Body, Location, Mutability, Operand, Place, Rvalue, Statement,
+    StatementKind,
+  },
   ty::{adjustment::AutoBorrowMutability, TyCtxt},
 };
 use rustc_span::Span;
@@ -223,7 +226,8 @@ pub struct PermissionsBoundary {
   #[serde(skip)]
   byte_location: BytePos,
   pub expected: Permissions,
-  pub actual: PermissionsData,
+  pub actual: Permissions,
+  pub data: PermissionsData,
   #[serde(skip_serializing_if = "Option::is_none")]
   pub expecting_flow: Option<FlowBoundary>,
 }
@@ -232,7 +236,7 @@ impl PermissionsBoundary {
   pub fn is_violation(&self) -> bool {
     macro_rules! is_missing {
       ($this:ident, $perm:ident) => {
-        ($this.expected.$perm && !$this.actual.permissions.$perm)
+        ($this.expected.$perm && !$this.actual.$perm)
       };
     }
 
@@ -336,6 +340,34 @@ impl std::fmt::Debug for PathBoundary {
   }
 }
 
+/// Get all local places within the body, sorted by their similarity to the given `HirId` place.
+fn locals_by_visible_distance<'tcx>(
+  tcx: TyCtxt<'tcx>,
+  id: HirId,
+  body: &Body<'tcx>,
+) -> Option<Place<'tcx>> {
+  use fuzzy_match::fuzzy_match;
+  use rustc_middle::mir::VarDebugInfoContents;
+
+  let map = tcx.hir();
+  // Get a textual representation of the path we're dealing with. Note, that this
+  // may be something like `*x` or `&x[0]` and not just `x`.
+  let node_str = tcx
+    .sess
+    .source_map()
+    .span_to_snippet(map.span(id))
+    .unwrap_or_default();
+
+  let all_local_places = body.var_debug_info.iter().filter_map(|debug_info| {
+    let VarDebugInfoContents::Place(p) = debug_info.value else {
+      return None;
+    };
+    Some((debug_info.name.as_str(), p))
+  });
+
+  fuzzy_match(&node_str, all_local_places)
+}
+
 // HACK: this is unsatisfying. Ideally, we would be able to take a (resolved) hir::Path
 // and turn it directly into its corresponding mir::Place, I (gavin)
 // haven't found a great way to do this, so for now, we consider all
@@ -349,64 +381,70 @@ impl std::fmt::Debug for PathBoundary {
 /// NOTE: candidates are expected to be given as an
 /// [*inorder*](https://en.wikipedia.org/wiki/Tree_traversal) HIR tree traversal.
 fn select_candidate_location<'tcx>(
-  _tcx: TyCtxt<'tcx>,
-  _body: &Body<'tcx>,
-  _hir_id: HirId,
+  tcx: TyCtxt<'tcx>,
+  body: &Body<'tcx>,
+  hir_id: HirId,
   subtract_from: impl FnOnce() -> Vec<(Location, Place<'tcx>)>,
   candidates: &[(Location, Place<'tcx>)],
 ) -> Option<(Location, Place<'tcx>)> {
-  if candidates.is_empty() {
-    return None;
-  }
-
-  if candidates.len() == 1 {
-    return Some(candidates[0]);
+  if candidates.len() <= 1 {
+    return candidates.first().copied();
   }
 
   let others = subtract_from();
   // Remove all candidates present in the subtraction set.
-  let candidates = candidates
-    .iter()
-    .filter(|t| !others.contains(t))
-    .collect::<Vec<_>>();
-
-  // The first usage contains the relevant Local,
-  // in most cases the first use will also be the desired
-  // Place but when indexing an array this isn't true.
-  // ```ignore
-  // let a = [0];
-  // let i0 = a[i];
-  //          ^^^ expands to:
-  //          // len_a = Len(a)
-  //          // assert 0 <= i < len_a
-  //          // copy a[i]
-  // ```
-  // For an array index, the first use is actually getting the
-  // length of the array, but we want to make sure to use the
-  // actual indexing. To achieve this we filter out all places
-  // with a different base Local, then we chooset he Place with
-  // the *most* projections.
-  let base_local = candidates.first()?.1.local;
-
-  let matching_locals = candidates
-    .into_iter()
-    .filter(|(_, p)| p.local == base_local);
-
-  // We first reverse the iterator because
-  // `max_by_key` takes the last matching value
-  // when there is a clash but we need the first.
-  matching_locals
-    .rev()
-    .max_by_key(|(_, p)| p.projection.len())
-    .copied()
+  let candidates = candidates.iter().filter(|t| !others.contains(t));
+
+  // From the list of local places sorted by similarity to the given `HirId`,
+  // pick the first one that matches the base local.
+  if let Some(similar_local) = locals_by_visible_distance(tcx, hir_id, body) {
+    log::debug!("Similar local found: {similar_local:?}");
+    candidates
+      .into_iter()
+      .find(|(_, can_place)| can_place.local == similar_local.local)
+      .copied()
+  } else {
+    // If no similar local is found, then we can do a "best effort" search.
+
+    let candidates = candidates.collect::<Vec<_>>();
+    // The first usage contains the relevant Local,
+    // in most cases the first use will also be the desired
+    // Place but when indexing an array this isn't true.
+    // ```ignore
+    // let a = [0];
+    // let i0 = a[i];
+    //          ^^^ expands to:
+    //          // len_a = Len(a)
+    //          // assert 0 <= i < len_a
+    //          // copy a[i]
+    // ```
+    // For an array index, the first use is actually getting the
+    // length of the array, but we want to make sure to use the
+    // actual indexing. To achieve this we filter out all places
+    // with a different base Local, then we choose the Place with
+    // the *most* projections.
+    let base_local = candidates.first()?.1.local;
+
+    let matching_locals = candidates
+      .into_iter()
+      .filter(|(_, p)| p.local == base_local);
+
+    // We first reverse the iterator because
+    // `max_by_key` takes the last matching value
+    // when there is a clash but we need the first.
+    matching_locals
+      .rev()
+      .max_by_key(|(_, p)| p.projection.len())
+      .copied()
+  }
 }
 
 /// Return the constraints that occur nested within a [`HirId`].
 ///
 /// Note, constraints involving regions belonging to the same SCC are removed.
-fn flow_constraints_at_hir_id<'a, 'tcx: 'a>(
-  ctxt: &'a PermissionsCtxt<'a, 'tcx>,
-  ir_mapper: &'a IRMapper<'a, 'tcx>,
+fn flow_constraints_at_hir_id<'tcx>(
+  ctxt: &PermissionsCtxt<'tcx>,
+  ir_mapper: &IRMapper<'tcx>,
   hir_id: HirId,
 ) -> Option<Vec<(Origin, Origin, Point)>> {
   let mir_locations =
@@ -543,34 +581,38 @@ fn get_flow_permission(
 /// given HIR node. This builds our set of candidate places
 /// that we consider for boundary resolution.
 #[allow(clippy::wildcard_in_or_patterns)]
-fn paths_at_hir_id<'a, 'tcx: 'a>(
+fn paths_at_hir_id<'tcx>(
   tcx: TyCtxt<'tcx>,
-  body: &'a Body<'tcx>,
-  ir_mapper: &'a IRMapper<'a, 'tcx>,
+  body: &'tcx Body<'tcx>,
+  ir_mapper: &IRMapper<'tcx>,
   hir_id: HirId,
 ) -> Option<Vec<(Location, Place<'tcx>)>> {
-  type TempBuff<'tcx> = SmallVec<[(Location, Place<'tcx>); 3]>;
-
-  let mir_locations_opt =
-    ir_mapper.get_mir_locations(hir_id, GatherDepth::Nested);
+  type UsedPlace<'tcx> = (Location, Place<'tcx>);
+  type UsedPlaces<'tcx> = SmallVec<[UsedPlace<'tcx>; 3]>;
+
+  fn maybe_in_op<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    body: &'tcx Body<'tcx>,
+    loc: Location,
+    op: &Operand<'tcx>,
+  ) -> Option<UsedPlace<'tcx>> {
+    op.as_place()
+      .and_then(|p| p.is_source_visible(tcx, body).then_some(p))
+      .map(|p| (loc, p))
+  }
 
   macro_rules! maybe_in_op {
-    ($loc:expr, $op:expr) => {
-      $op
-        .as_place()
-        .and_then(|p| p.is_source_visible(tcx, body).then_some(p))
-        .map(|p| smallvec![($loc, p)])
-        .unwrap_or(smallvec![])
+    ($loc:expr, $op:expr $(,$ops:expr)*) => {
+      maybe_in_op(tcx, body, $loc, $op).into_iter()
+        $(.chain(maybe_in_op(tcx, body, $loc, $ops).into_iter()))*
+        .collect()
     };
-    ($loc:expr, $op1:expr, $op2:expr) => {{
-      let mut v: TempBuff = maybe_in_op!($loc, $op1);
-      let mut o: TempBuff = maybe_in_op!($loc, $op2);
-      v.append(&mut o);
-      v
-    }};
   }
 
-  let look_in_rvalue = |rvalue: &Rvalue<'tcx>, loc: Location| -> TempBuff {
+  let mir_locations_opt =
+    ir_mapper.get_mir_locations(hir_id, GatherDepth::Nested);
+
+  let look_in_rvalue = |rvalue: &Rvalue<'tcx>, loc: Location| -> UsedPlaces {
     match rvalue {
       // Nested operand cases
       Rvalue::Use(op)
@@ -581,41 +623,44 @@ fn paths_at_hir_id<'a, 'tcx: 'a>(
 
       // Given place cases.
       Rvalue::Ref(_, _, place)
-        | Rvalue::AddressOf(_, place)
         | Rvalue::Len(place)
         | Rvalue::Discriminant(place)
         | Rvalue::CopyForDeref(place)
+        | Rvalue::RawPtr(_, place)
         if place.is_source_visible(tcx, body) =>
       {
         smallvec![(loc, *place)]
       }
 
-      // Two operand cases
-      Rvalue::BinaryOp(_, box (left_op, right_op))
-        | Rvalue::CheckedBinaryOp(_, box (left_op, right_op)) => {
-          maybe_in_op!(loc, left_op, right_op)
-        }
+      // Operand case
+      Rvalue::BinaryOp(_, box (left_op, right_op)) => {
+        maybe_in_op!(loc, left_op, right_op)
+      }
+
+      Rvalue::Aggregate(_, fields) => {
+        fields.iter().filter_map(|op| maybe_in_op(tcx, body, loc, op)).collect()
+      }
 
       // Unimplemented cases, ignore nested information for now.
-      //
-      // These are separated in the or because they aren't implemented,
-      // but still silently ignored.
       Rvalue::ThreadLocalRef(..)
         | Rvalue::NullaryOp(..)
-        | Rvalue::Aggregate(..)
-
-      // Wildcard for catching the previous guarded matches.
-        | _ => {
-          log::warn!("couldn't find in RVALUE {rvalue:?}");
-          smallvec![]
-        }
+        // Without guard
+        | Rvalue::Ref(..)
+        | Rvalue::Len(..)
+        | Rvalue::Discriminant(..)
+        | Rvalue::CopyForDeref(..)
+        | Rvalue::RawPtr(..) => {
+          log::warn!("Unimplemented rvalue case: {rvalue:?}");
+          SmallVec::default()
+        },
     }
   };
 
-  let look_in_statement = |stmt: &Statement<'tcx>, loc: Location| -> TempBuff {
-    match &stmt.kind {
+  let look_in_statement =
+    |stmt: &Statement<'tcx>, loc: Location| -> UsedPlaces {
+      match &stmt.kind {
       StatementKind::Assign(box (lhs_place, ref rvalue)) => {
-        let mut found_so_far: TempBuff = look_in_rvalue(rvalue, loc);
+        let mut found_so_far: UsedPlaces = look_in_rvalue(rvalue, loc);
         if lhs_place.is_source_visible(tcx, body) {
           found_so_far.push((loc, *lhs_place));
         }
@@ -651,9 +696,10 @@ fn paths_at_hir_id<'a, 'tcx: 'a>(
       | StatementKind::Coverage(..)
       | StatementKind::Intrinsic(..)
       | StatementKind::ConstEvalCounter
+      | StatementKind::BackwardIncompatibleDropHint { .. }
       | StatementKind::Nop => smallvec![],
     }
-  };
+    };
 
   let mir_locations = mir_locations_opt?
     .values()
@@ -669,9 +715,9 @@ fn paths_at_hir_id<'a, 'tcx: 'a>(
   Some(mir_locations)
 }
 
-fn path_to_perm_boundary<'a, 'tcx: 'a>(
+fn path_to_perm_boundary(
   path_boundary: PathBoundary,
-  analysis: &'a AquascopeAnalysis<'a, 'tcx>,
+  analysis: &AquascopeAnalysis<'_>,
 ) -> Option<PermissionsBoundary> {
   let ctxt = &analysis.permissions;
   let ir_mapper = &analysis.ir_mapper;
@@ -702,11 +748,11 @@ fn path_to_perm_boundary<'a, 'tcx: 'a>(
       &path_locations,
     )?;
 
-    log::debug!("Chosen place at location {place:#?} {loc:#?} other options: {path_locations:#?}");
-
     let point = ctxt.location_to_point(loc);
     let path = ctxt.place_to_path(&place);
 
+    log::debug!("Chosen place at location {place:#?} {loc:#?} ({point:?},{path:?})\nOther options: {path_locations:#?}");
+
     Some((point, path))
   };
 
@@ -722,13 +768,14 @@ fn path_to_perm_boundary<'a, 'tcx: 'a>(
       })
     })
     .map(|(point, path)| {
-      let actual = ctxt.permissions_data_at_point(path, point);
+      let data = ctxt.permissions_data_at_point(path, point);
       let expected = path_boundary.expected;
+      let actual = data.permissions_ignore_liveness();
 
       let expecting_flow =
         get_flow_permission(analysis, path_boundary.flow_context, hir_id);
 
-      log::debug!("Permissions data:\n{actual:#?}\n{expecting_flow:#?}");
+      log::debug!("Permissions data for {}:\n{actual:#?}\n{expected:#?}\n{expecting_flow:#?}", hir.node_to_string(path_boundary.hir_id));
 
       let span = path_boundary
         .location
@@ -748,6 +795,7 @@ fn path_to_perm_boundary<'a, 'tcx: 'a>(
         byte_location,
         expected: expected.into(),
         actual,
+        data,
         expecting_flow,
       }
     });
@@ -763,8 +811,8 @@ fn path_to_perm_boundary<'a, 'tcx: 'a>(
 }
 
 #[allow(clippy::module_name_repetitions)]
-pub fn compute_permission_boundaries<'a, 'tcx: 'a>(
-  analysis: &AquascopeAnalysis<'a, 'tcx>,
+pub fn compute_permission_boundaries(
+  analysis: &AquascopeAnalysis<'_>,
 ) -> Result<Vec<PermissionsBoundary>> {
   let ctxt = &analysis.permissions;
 
@@ -781,7 +829,7 @@ pub fn compute_permission_boundaries<'a, 'tcx: 'a>(
 
   let boundaries = path_use_points
     .filter(|pb| {
-      first_error_span_opt.map_or(true, |error_span| {
+      first_error_span_opt.is_none_or(|error_span| {
         pb.expecting_flow.is_some() || {
           let error_range =
             ByteRange::from_span(error_span, ctxt.tcx.sess.source_map())
@@ -794,3 +842,29 @@ pub fn compute_permission_boundaries<'a, 'tcx: 'a>(
 
   Ok(boundaries)
 }
+
+#[cfg(test)]
+mod test {
+  use fuzzy_match::fuzzy_match;
+
+  #[test]
+  fn fuzzy_search_0() {
+    let search = "&*x[i]";
+    let haystack = vec![("x", 0), ("y", 1), ("z", 2)];
+    assert_eq!(Some(0), fuzzy_match(search, haystack));
+  }
+
+  #[test]
+  fn fuzzy_search_1() {
+    let search = "&&&&&z";
+    let haystack = vec![("x", 0), ("y", 1), ("z", 2)];
+    assert_eq!(Some(2), fuzzy_match(search, haystack));
+  }
+
+  #[test]
+  fn fuzzy_search_2() {
+    let search = "y[..a]";
+    let haystack = vec![("x", 0), ("y", 1), ("z", 2)];
+    assert_eq!(Some(1), fuzzy_match(search, haystack));
+  }
+}
diff --git a/crates/aquascope/src/analysis/boundaries/path_visitor.rs b/crates/aquascope/src/analysis/boundaries/path_visitor.rs
index bb4181819..fa5f1b49b 100644
--- a/crates/aquascope/src/analysis/boundaries/path_visitor.rs
+++ b/crates/aquascope/src/analysis/boundaries/path_visitor.rs
@@ -11,7 +11,7 @@ use rustc_middle::{
   hir::nested_filter::OnlyBodies,
   ty::{
     adjustment::{Adjust, AutoBorrow},
-    ParamEnv, TyCtxt, TypeckResults,
+    TyCtxt, TypeckResults, TypingEnv,
   },
 };
 use rustc_span::Span;
@@ -23,15 +23,15 @@ use crate::analysis::permissions::PermissionsCtxt;
 // The current region flow context for outer statements and returns.
 fluid_let!(pub static FLOW_CONTEXT: HirId);
 
-struct HirExprScraper<'a, 'tcx: 'a> {
+struct HirExprScraper<'tcx> {
   tcx: TyCtxt<'tcx>,
-  typeck_res: &'a TypeckResults<'tcx>,
-  param_env: ParamEnv<'tcx>,
+  typeck_res: &'tcx TypeckResults<'tcx>,
+  typing_env: TypingEnv<'tcx>,
   data: Vec<PathBoundary>,
   unsupported_feature: Option<(Span, String)>,
 }
 
-impl<'a, 'tcx: 'a> HirExprScraper<'a, 'tcx> {
+impl HirExprScraper<'_> {
   fn get_adjusted_permissions(&self, expr: &Expr) -> ExpectedPermissions {
     let ty_adj = self.typeck_res.expr_ty_adjusted(expr);
     let adjs = self.typeck_res.expr_adjustments(expr);
@@ -39,7 +39,7 @@ impl<'a, 'tcx: 'a> HirExprScraper<'a, 'tcx> {
     log::debug!("Path TY-ADJ: {:#?} from {:#?}", ty_adj, adjs);
 
     let is_auto_borrow = adjs.iter().find_map(|adj| {
-      if let Adjust::Borrow(AutoBorrow::Ref(_, m)) = adj.kind {
+      if let Adjust::Borrow(AutoBorrow::Ref(m)) = adj.kind {
         Some(m)
       } else {
         None
@@ -53,7 +53,7 @@ impl<'a, 'tcx: 'a> HirExprScraper<'a, 'tcx> {
     // At this point the usage is either a move or a copy. We
     // can determine this whether or not the type of the path
     // is copyable or not.
-    if ty_adj.is_copyable(self.tcx, self.param_env) {
+    if ty_adj.is_copyable(self.tcx, self.typing_env) {
       ExpectedPermissions::from_copy()
     } else {
       ExpectedPermissions::from_move()
@@ -61,7 +61,7 @@ impl<'a, 'tcx: 'a> HirExprScraper<'a, 'tcx> {
   }
 }
 
-impl<'a, 'tcx: 'a> Visitor<'tcx> for HirExprScraper<'a, 'tcx> {
+impl<'tcx> Visitor<'tcx> for HirExprScraper<'tcx> {
   type NestedFilter = OnlyBodies;
 
   fn nested_visit_map(&mut self) -> Self::Map {
@@ -71,12 +71,12 @@ impl<'a, 'tcx: 'a> Visitor<'tcx> for HirExprScraper<'a, 'tcx> {
   // Visiting statements / body is only used for specifying a
   // region flow context. This would not be used for RWO
   // path boundaries.
-  fn visit_body(&mut self, body: &'tcx Body) {
+  fn visit_body(&mut self, body: &Body<'tcx>) {
     fluid_set!(FLOW_CONTEXT, &body.value.hir_id);
     intravisit::walk_body(self, body);
   }
 
-  fn visit_stmt(&mut self, stmt: &'tcx Stmt) {
+  fn visit_stmt(&mut self, stmt: &'tcx Stmt<'tcx>) {
     fluid_set!(FLOW_CONTEXT, &stmt.hir_id);
     intravisit::walk_stmt(self, stmt);
   }
@@ -255,16 +255,16 @@ impl<'a, 'tcx: 'a> Visitor<'tcx> for HirExprScraper<'a, 'tcx> {
   }
 }
 
-pub(super) fn get_path_boundaries<'a, 'tcx: 'a>(
-  ctxt: &'a PermissionsCtxt<'a, 'tcx>,
+pub(super) fn get_path_boundaries(
+  ctxt: &PermissionsCtxt<'_>,
 ) -> Result<Vec<PathBoundary>> {
   let tcx = ctxt.tcx;
   let body_id = ctxt.body_id;
   let typeck_res = tcx.typeck_body(ctxt.body_id);
-  let param_env = ctxt.param_env;
+  let typing_env = ctxt.typing_env;
   let mut finder = HirExprScraper {
     tcx,
-    param_env,
+    typing_env,
     typeck_res,
     unsupported_feature: None,
     data: Vec::default(),
diff --git a/crates/aquascope/src/analysis/find_bindings.rs b/crates/aquascope/src/analysis/find_bindings.rs
index f6f47eed6..56ff4390f 100644
--- a/crates/aquascope/src/analysis/find_bindings.rs
+++ b/crates/aquascope/src/analysis/find_bindings.rs
@@ -1,7 +1,7 @@
 use rustc_data_structures::fx::FxHashMap as HashMap;
 use rustc_hir::{
   intravisit::{self, Visitor},
-  BindingAnnotation, HirId, Pat, PatKind,
+  BindingMode, HirId, Pat, PatKind,
 };
 // use rustc_hir_analysis;
 use rustc_middle::{hir::nested_filter::OnlyBodies, ty::TyCtxt};
@@ -9,7 +9,7 @@ use rustc_middle::{hir::nested_filter::OnlyBodies, ty::TyCtxt};
 struct BindingFinder<'tcx> {
   tcx: TyCtxt<'tcx>,
   // Mapping a HirId (identifier) with it's binding annotations.
-  bindings: HashMap<HirId, BindingAnnotation>,
+  bindings: HashMap<HirId, BindingMode>,
 }
 
 impl<'tcx> Visitor<'tcx> for BindingFinder<'tcx> {
@@ -29,7 +29,7 @@ impl<'tcx> Visitor<'tcx> for BindingFinder<'tcx> {
   }
 }
 
-pub fn find_bindings(tcx: TyCtxt) -> HashMap<HirId, BindingAnnotation> {
+pub fn find_bindings(tcx: TyCtxt) -> HashMap<HirId, BindingMode> {
   let mut finder = BindingFinder {
     tcx,
     bindings: HashMap::default(),
diff --git a/crates/aquascope/src/analysis/ir_mapper/body_graph.rs b/crates/aquascope/src/analysis/ir_mapper/body_graph.rs
index dab2403bd..61d5a09d0 100644
--- a/crates/aquascope/src/analysis/ir_mapper/body_graph.rs
+++ b/crates/aquascope/src/analysis/ir_mapper/body_graph.rs
@@ -1,4 +1,4 @@
-use rustc_data_structures::{captures::Captures, graph::*};
+use rustc_data_structures::graph::*;
 use rustc_middle::mir::{
   BasicBlock, BasicBlockData, BasicBlocks, Body, Location, Terminator,
   TerminatorKind,
@@ -11,11 +11,11 @@ use smallvec::SmallVec;
 /// regular control-flow. This removes cleanup blocks or those which
 /// fall in unwind paths. When mapping back to source-level constructs
 /// this is almost certainly what you want to use.
-pub(crate) struct CleanedBody<'a, 'tcx: 'a>(pub &'a Body<'tcx>);
+pub(crate) struct CleanedBody<'tcx>(pub &'tcx Body<'tcx>);
 
 #[allow(dead_code)]
-impl<'a, 'tcx: 'a> CleanedBody<'a, 'tcx> {
-  pub fn body(&self) -> &'a Body<'tcx> {
+impl<'tcx> CleanedBody<'tcx> {
+  pub fn body(&self) -> &'tcx Body<'tcx> {
     self.0
   }
 
@@ -57,9 +57,7 @@ impl<'a, 'tcx: 'a> CleanedBody<'a, 'tcx> {
     self.body().basic_blocks[block].terminator()
   }
 
-  pub fn blocks(
-    &self,
-  ) -> impl Iterator<Item = BasicBlock> + Captures<'a> + Captures<'tcx> + '_ {
+  pub fn blocks(&self) -> impl Iterator<Item = BasicBlock> + use<'tcx, '_> {
     self
       .0
       .basic_blocks
@@ -78,7 +76,7 @@ impl<'a, 'tcx: 'a> CleanedBody<'a, 'tcx> {
   }
 
   fn keep_block(bb: &BasicBlockData) -> bool {
-    !bb.is_cleanup && !bb.is_empty_unreachable()
+    !bb.is_cleanup && !bb.is_unreachable()
   }
 
   fn is_imaginary_target(
@@ -99,33 +97,23 @@ impl<'a, 'tcx: 'a> CleanedBody<'a, 'tcx> {
 // -----------
 // Graph impls
 
-impl DirectedGraph for CleanedBody<'_, '_> {
+impl DirectedGraph for CleanedBody<'_> {
   type Node = BasicBlock;
-}
-
-impl WithStartNode for CleanedBody<'_, '_> {
-  fn start_node(&self) -> Self::Node {
-    self.0.basic_blocks.start_node()
-  }
-}
 
-impl<'tcx> WithNumNodes for CleanedBody<'_, 'tcx> {
   fn num_nodes(&self) -> usize {
     self.0.basic_blocks.len()
   }
 }
 
-impl<'tcx> GraphSuccessors<'_> for CleanedBody<'_, 'tcx> {
-  type Item = BasicBlock;
-  type Iter = smallvec::IntoIter<[BasicBlock; 4]>;
+impl StartNode for CleanedBody<'_> {
+  fn start_node(&self) -> Self::Node {
+    self.0.basic_blocks.start_node()
+  }
 }
 
-impl<'tcx> WithSuccessors for CleanedBody<'_, 'tcx> {
-  fn successors(
-    &self,
-    node: Self::Node,
-  ) -> <Self as GraphSuccessors<'_>>::Iter {
-    <BasicBlocks as WithSuccessors>::successors(&self.0.basic_blocks, node)
+impl Successors for CleanedBody<'_> {
+  fn successors(&self, node: Self::Node) -> impl Iterator<Item = Self::Node> {
+    <BasicBlocks as Successors>::successors(&self.0.basic_blocks, node)
       .filter(|bb| {
         let from_data = &self.0.basic_blocks[*bb];
         CleanedBody::keep_block(from_data)
@@ -136,23 +124,25 @@ impl<'tcx> WithSuccessors for CleanedBody<'_, 'tcx> {
   }
 }
 
-impl<'tcx> GraphPredecessors<'_> for CleanedBody<'_, 'tcx> {
-  type Item = BasicBlock;
-  type Iter = smallvec::IntoIter<[BasicBlock; 4]>;
-}
-
-impl<'tcx> WithPredecessors for CleanedBody<'_, 'tcx> {
-  fn predecessors(
-    &self,
-    node: Self::Node,
-  ) -> <Self as GraphSuccessors<'_>>::Iter {
-    <BasicBlocks as WithPredecessors>::predecessors(&self.0.basic_blocks, node)
+impl Predecessors for CleanedBody<'_> {
+  fn predecessors(&self, node: Self::Node) -> impl Iterator<Item = Self::Node> {
+    <BasicBlocks as Predecessors>::predecessors(&self.0.basic_blocks, node)
       .filter(|bb| CleanedBody::keep_block(&self.0.basic_blocks[*bb]))
       .collect::<SmallVec<[BasicBlock; 4]>>()
       .into_iter()
   }
 }
 
+trait BasicBlockDataExt {
+  fn is_unreachable(&self) -> bool;
+}
+
+impl BasicBlockDataExt for BasicBlockData<'_> {
+  fn is_unreachable(&self) -> bool {
+    matches!(self.terminator().kind, TerminatorKind::Unreachable)
+  }
+}
+
 #[cfg(test)]
 mod test {
   use rustc_utils::BodyExt;
diff --git a/crates/aquascope/src/analysis/ir_mapper/mod.rs b/crates/aquascope/src/analysis/ir_mapper/mod.rs
index a4c222a02..20d1412de 100644
--- a/crates/aquascope/src/analysis/ir_mapper/mod.rs
+++ b/crates/aquascope/src/analysis/ir_mapper/mod.rs
@@ -5,26 +5,26 @@ pub(crate) mod mir_locations;
 pub(crate) mod post_dominators;
 // pub(crate) mod region_name;
 
-pub(crate) use body_graph::CleanedBody;
-pub(crate) use mir_locations::MirOrderedLocations;
-use post_dominators::AllPostDominators;
 use rustc_data_structures::{
   fx::{FxHashMap as HashMap, FxHashSet as HashSet},
   graph::{dominators::Dominators, *},
 };
 use rustc_hir::{self as hir, HirId};
 use rustc_middle::{
-  mir::{
-    self, visit::Visitor as MirVisitor, BasicBlock, Body, Location, Place,
-  },
+  mir::{self, visit::Visitor as MirVisitor, BasicBlock, Body, Location},
   ty::TyCtxt,
 };
 use rustc_utils::BodyExt;
 
-pub struct IRMapper<'a, 'tcx> {
-  pub(crate) cleaned_graph: CleanedBody<'a, 'tcx>,
+use self::post_dominators::AllPostDominators;
+pub(crate) use self::{
+  body_graph::CleanedBody, mir_locations::MirOrderedLocations,
+};
+
+pub struct IRMapper<'tcx> {
+  pub(crate) cleaned_graph: CleanedBody<'tcx>,
   tcx: TyCtxt<'tcx>,
-  body: &'a Body<'tcx>,
+  body: &'tcx Body<'tcx>,
   hir_to_mir: HashMap<HirId, HashSet<Location>>,
   gather_mode: GatherMode,
   pub(crate) dominators: Dominators<BasicBlock>,
@@ -67,13 +67,10 @@ pub enum GatherDepth {
   Nested,
 }
 
-impl<'a, 'tcx> IRMapper<'a, 'tcx>
-where
-  'tcx: 'a,
-{
+impl<'tcx> IRMapper<'tcx> {
   pub fn new(
     tcx: TyCtxt<'tcx>,
-    body: &'a Body<'tcx>,
+    body: &'tcx Body<'tcx>,
     gather_mode: GatherMode,
   ) -> Self {
     let cleaned_graph = CleanedBody(body);
@@ -137,9 +134,13 @@ where
     )
   }
 
-  pub fn local_assigned_place(&self, local: &hir::Local) -> Vec<Place<'tcx>> {
+  pub fn local_assigned_place(
+    &self,
+    local: &hir::LetStmt,
+  ) -> Vec<mir::Place<'tcx>> {
     use either::Either;
     use mir::{FakeReadCause as FRC, StatementKind as SK};
+
     let id = local.hir_id;
     self.get_mir_locations(id, GatherDepth::Outer).map_or_else(
       Vec::default,
@@ -296,7 +297,7 @@ where
 // -------------------------------------------------------------------
 // Gather the HIR -> MIR relationships for statements and terminators.
 
-impl<'tcx> MirVisitor<'tcx> for IRMapper<'_, 'tcx> {
+impl<'tcx> MirVisitor<'tcx> for IRMapper<'tcx> {
   fn visit_basic_block_data(
     &mut self,
     block: mir::BasicBlock,
diff --git a/crates/aquascope/src/analysis/ir_mapper/post_dominators.rs b/crates/aquascope/src/analysis/ir_mapper/post_dominators.rs
index 43c2ec60d..aed41cb3c 100644
--- a/crates/aquascope/src/analysis/ir_mapper/post_dominators.rs
+++ b/crates/aquascope/src/analysis/ir_mapper/post_dominators.rs
@@ -1,6 +1,6 @@
 use rustc_data_structures::graph::*;
 use rustc_index::{
-  bit_set::{HybridBitSet, SparseBitMatrix},
+  bit_set::{ChunkedBitSet, SparseBitMatrix},
   Idx,
 };
 use rustc_utils::mir::control_dependencies::PostDominators;
@@ -21,7 +21,7 @@ impl<Node: Idx> AllPostDominators<Node> {
     for exit in exits {
       let exit_pdom = PostDominators::build(graph, exit);
       for node in all_nodes.clone() {
-        let mut is_pdom = HybridBitSet::new_empty(graph.num_nodes());
+        let mut is_pdom = ChunkedBitSet::new_empty(graph.num_nodes());
         if let Some(iter) = exit_pdom.post_dominators(node) {
           for other in iter {
             is_pdom.insert(other);
@@ -66,35 +66,20 @@ mod tests {
 
   impl<N: Idx> DirectedGraph for VG<N> {
     type Node = N;
-  }
-
-  impl<'graph, N: Idx> GraphSuccessors<'graph> for VG<N> {
-    type Item = N;
-    type Iter = smallvec::IntoIter<[N; 10]>;
-  }
 
-  impl<'graph, N: Idx> GraphPredecessors<'graph> for VG<N> {
-    type Item = N;
-    type Iter = smallvec::IntoIter<[N; 10]>;
-  }
-
-  impl<N: Idx> WithStartNode for VG<N> {
-    fn start_node(&self) -> N {
-      self.source
+    fn num_nodes(&self) -> usize {
+      self.forward.num_nodes()
     }
   }
 
-  impl<N: Idx> WithNumNodes for VG<N> {
-    fn num_nodes(&self) -> usize {
-      self.forward.num_nodes()
+  impl<N: Idx> StartNode for VG<N> {
+    fn start_node(&self) -> Self::Node {
+      self.source
     }
   }
 
-  impl<N: Idx + Ord> WithSuccessors for VG<N> {
-    fn successors(
-      &self,
-      node: Self::Node,
-    ) -> <Self as GraphSuccessors<'_>>::Iter {
+  impl<N: Idx + Ord> Successors for VG<N> {
+    fn successors(&self, node: Self::Node) -> impl Iterator<Item = Self::Node> {
       self
         .forward
         .successors(node)
@@ -105,11 +90,11 @@ mod tests {
     }
   }
 
-  impl<N: Idx + Ord> WithPredecessors for VG<N> {
+  impl<N: Idx + Ord> Predecessors for VG<N> {
     fn predecessors(
       &self,
       node: Self::Node,
-    ) -> <Self as GraphSuccessors<'_>>::Iter {
+    ) -> impl Iterator<Item = Self::Node> {
       self
         .backward
         .successors(node)
diff --git a/crates/aquascope/src/analysis/mod.rs b/crates/aquascope/src/analysis/mod.rs
index b94ebc9d3..3b2ded793 100644
--- a/crates/aquascope/src/analysis/mod.rs
+++ b/crates/aquascope/src/analysis/mod.rs
@@ -218,18 +218,16 @@ where
   smoothed_elements
 }
 
-pub fn compute_permissions<'a, 'tcx>(
+pub fn compute_permissions<'tcx>(
   tcx: TyCtxt<'tcx>,
   body_id: BodyId,
-  body_with_facts: &'a BodyWithBorrowckFacts<'tcx>,
-) -> PermissionsCtxt<'a, 'tcx> {
+  body_with_facts: &'tcx BodyWithBorrowckFacts<'tcx>,
+) -> PermissionsCtxt<'tcx> {
   BODY_ID_STACK.with(|stack| {
     stack.borrow_mut().push(body_id);
 
     let permissions = permissions::compute(tcx, body_id, body_with_facts);
 
-    permissions::utils::dump_permissions_with_mir(&permissions);
-
     permissions
   })
 }
@@ -247,9 +245,9 @@ pub enum AquascopeError {
 
 pub type AquascopeResult<T> = ::std::result::Result<T, AquascopeError>;
 
-pub struct AquascopeAnalysis<'a, 'tcx: 'a> {
-  pub(crate) permissions: PermissionsCtxt<'a, 'tcx>,
-  pub(crate) ir_mapper: IRMapper<'a, 'tcx>,
+pub struct AquascopeAnalysis<'tcx> {
+  pub(crate) permissions: PermissionsCtxt<'tcx>,
+  pub(crate) ir_mapper: IRMapper<'tcx>,
 }
 
 impl From<anyhow::Error> for AquascopeError {
@@ -270,7 +268,7 @@ pub struct AnalysisOutput {
   pub move_regions: MoveRegions,
 }
 
-impl<'a, 'tcx: 'a> AquascopeAnalysis<'a, 'tcx> {
+impl<'tcx> AquascopeAnalysis<'tcx> {
   pub fn new(tcx: TyCtxt<'tcx>, body_id: BodyId) -> Self {
     let def_id = tcx.hir().body_owner_def_id(body_id);
     let bwf = borrowck_facts::get_body_with_borrowck_facts(tcx, def_id);
@@ -342,7 +340,7 @@ impl<'a, 'tcx: 'a> AquascopeAnalysis<'a, 'tcx> {
       .filter_map(|(loan, _)| {
         // TODO: using `reserve_location` is not exactly accurate because this
         // could be a two-phase borrow. This needs to use the `activation_location`.
-        let loan_loc = self.permissions.borrow_set[*loan].reserve_location;
+        let loan_loc = self.permissions.borrow_set[*loan].reserve_location();
         let loan_span = self.permissions.location_to_span(loan_loc);
 
         let span = loan_span
@@ -389,7 +387,12 @@ impl<'a, 'tcx: 'a> AquascopeAnalysis<'a, 'tcx> {
 
         let loan_live_at = &self.permissions.polonius_output.loan_live_at;
         let active_nodes = self
-          .key_to_spans(**loan, loan_live_at, start_span, end_span)
+          .key_to_spans(
+            **loan,
+            &loan_live_at.clone().into_iter().collect(),
+            start_span,
+            end_span,
+          )
           .into_iter()
           .map(|s| self.span_to_range(s))
           .collect::<Vec<_>>();
@@ -448,10 +451,7 @@ impl<'a, 'tcx: 'a> AquascopeAnalysis<'a, 'tcx> {
         // strictly after the initial action.
         // Also, if the move point was removed for not being visible then
         // we can just ignore computing the highlighted ranges as well.
-        let Some(lo) = move_points.get(&move_key).map(|s| s.lo()) else {
-          return None;
-        };
-
+        let lo = move_points.get(&move_key).map(|s| s.lo())?;
         let points = self
           .points_to_spans(
             points
diff --git a/crates/aquascope/src/analysis/permissions/context.rs b/crates/aquascope/src/analysis/permissions/context.rs
index 9f6d5bd29..4ed236622 100644
--- a/crates/aquascope/src/analysis/permissions/context.rs
+++ b/crates/aquascope/src/analysis/permissions/context.rs
@@ -11,16 +11,16 @@
 //! about the theory of the permissions derivation.
 
 use polonius_engine::{AllFacts, FactTypes, Output as PEOutput};
-use rustc_borrowck::{
-  borrow_set::{BorrowData, BorrowSet},
-  consumers::{BodyWithBorrowckFacts, LocationTable, RichLocation, RustcFacts},
+use rustc_borrowck::consumers::{
+  BodyWithBorrowckFacts, BorrowData, BorrowSet, LocationTable, RichLocation,
+  RustcFacts,
 };
 use rustc_data_structures::fx::{FxHashMap as HashMap, FxHashSet as HashSet};
 use rustc_hir::{def_id::DefId, BodyId, Mutability};
 use rustc_index::IndexVec;
 use rustc_middle::{
   mir::{BorrowKind, Local, Location, Place, ProjectionElem},
-  ty::{self, ParamEnv, Ty, TyCtxt},
+  ty::{self, Ty, TyCtxt, TypingEnv},
 };
 use rustc_mir_dataflow::move_paths::MoveData;
 use rustc_span::Span;
@@ -36,9 +36,9 @@ use crate::analysis::permissions::{
 /// A path as defined in rustc.
 type MoveablePath = <RustcFacts as FactTypes>::Path;
 
-pub struct PermissionsCtxt<'a, 'tcx> {
+pub struct PermissionsCtxt<'tcx> {
   pub tcx: TyCtxt<'tcx>,
-  pub polonius_input_facts: &'a AllFacts<RustcFacts>,
+  pub polonius_input_facts: &'tcx AllFacts<RustcFacts>,
   pub polonius_output: PEOutput<RustcFacts>,
 
   /// Program facts unique to Aquascope.
@@ -51,18 +51,18 @@ pub struct PermissionsCtxt<'a, 'tcx> {
   pub permissions_output: Output<AquascopeFacts>,
   pub body_id: BodyId,
   pub def_id: DefId,
-  pub body_with_facts: &'a BodyWithBorrowckFacts<'tcx>,
+  pub body_with_facts: &'tcx BodyWithBorrowckFacts<'tcx>,
   pub borrow_set: BorrowSet<'tcx>,
   pub move_data: MoveData<'tcx>,
   pub loan_regions: Option<HashMap<Loan, (Point, Point)>>,
   pub locals_are_invalidated_at_exit: bool,
-  pub(crate) param_env: ParamEnv<'tcx>,
+  pub(crate) typing_env: TypingEnv<'tcx>,
   pub(crate) place_data: IndexVec<Path, Place<'tcx>>,
   pub(crate) rev_lookup: HashMap<Local, Vec<Path>>,
   pub(crate) region_flows: Option<RegionFlows>,
 }
 
-impl<'a, 'tcx> PermissionsCtxt<'a, 'tcx> {
+impl<'tcx> PermissionsCtxt<'tcx> {
   pub fn new_path(&mut self, place: Place<'tcx>) -> Path {
     let place = place.normalize(self.tcx, self.def_id);
     let new_path = self.place_data.push(place);
@@ -125,7 +125,11 @@ impl<'a, 'tcx> PermissionsCtxt<'a, 'tcx> {
 
   pub fn path_to_moveable_path(&self, p: Path) -> MoveablePath {
     let place = self.path_to_place(p);
-    self.move_data.rev_lookup.find_local(place.local)
+    self
+      .move_data
+      .rev_lookup
+      .find_local(place.local)
+      .unwrap_or_else(|| panic!("Missing local: {:?}", place.local))
   }
 
   pub fn moveable_path_to_path(&self, mp: MoveablePath) -> Path {
@@ -192,7 +196,7 @@ impl<'a, 'tcx> PermissionsCtxt<'a, 'tcx> {
   }
 
   pub fn is_mutable_borrow(&self, brw: &BorrowData<'tcx>) -> bool {
-    matches!(brw.kind, BorrowKind::Mut { .. })
+    matches!(brw.kind(), BorrowKind::Mut { .. })
   }
 
   pub fn is_mutable_loan(&self, loan: Loan) -> bool {
@@ -210,7 +214,7 @@ impl<'a, 'tcx> PermissionsCtxt<'a, 'tcx> {
       .polonius_output
       .var_live_on_entry
       .get(&point)
-      .map_or(false, |live_vars| live_vars.contains(&var))
+      .is_some_and(|live_vars| live_vars.contains(&var))
   }
 
   /// On use would the given path be copied?
@@ -218,7 +222,7 @@ impl<'a, 'tcx> PermissionsCtxt<'a, 'tcx> {
     let body = &self.body_with_facts.body;
     let place = self.path_to_place(path);
     let ty = place.ty(&body.local_decls, self.tcx).ty;
-    ty.is_copyable(self.tcx, self.param_env)
+    ty.is_copyable(self.tcx, self.typing_env)
   }
 
   /// Can this path be written to?
@@ -290,17 +294,12 @@ impl<'a, 'tcx> PermissionsCtxt<'a, 'tcx> {
       is_live: true,
       type_droppable: true,
       type_writeable: true,
-      type_copyable: ty.is_copyable(self.tcx, self.param_env),
+      type_copyable: ty.is_copyable(self.tcx, self.typing_env),
       path_moved: None,
       path_uninitialized: false,
       loan_read_refined: None,
       loan_write_refined: None,
       loan_drop_refined: None,
-      permissions: Permissions {
-        read: true,
-        write: true,
-        drop: true,
-      },
     }
   }
 
@@ -345,6 +344,8 @@ impl<'a, 'tcx> PermissionsCtxt<'a, 'tcx> {
     path: Path,
     point: Point,
   ) -> PermissionsData {
+    log::trace!("permissions_data_at_point: {:?} at {:?}", path, point);
+
     let empty_hash_move = &HashMap::default();
     let empty_hash_loan = &HashMap::default();
     let empty_set = &HashSet::default();
@@ -380,36 +381,6 @@ impl<'a, 'tcx> PermissionsCtxt<'a, 'tcx> {
     let loan_drop_refined: Option<LoanKey> =
       loan_drop_refined.get(path).map(Into::<LoanKey>::into);
 
-    let mem_uninit = path_moved.is_some() || path_uninitialized;
-
-    // An English description of the previous Datalog rules:
-    //
-    // A path is readable IFF:
-    // - it is not moved.
-    // - there doesn't exist a read-refining loan at this point.
-    //
-    // A path is writeable IFF:
-    // - the path's declared type allows for mutability.
-    // - the path is readable (you can't write if you can't read)
-    //   this implies that the path isn't moved.
-    // - there doesn't exist a write-refining loan at this point.
-    //
-    // A path is droppable(without copy) IFF:
-    // - the path's declared type is droppable.
-    // - it isn't moved.
-    // - no drop-refining loan exists at this point.
-    let permissions = if !is_live {
-      Permissions::bottom()
-    } else {
-      let read = !mem_uninit && loan_read_refined.is_none();
-
-      let write = type_writeable && read && loan_write_refined.is_none();
-
-      let drop = type_droppable && read && loan_drop_refined.is_none();
-
-      Permissions { read, write, drop }
-    };
-
     PermissionsData {
       type_droppable,
       type_writeable,
@@ -420,7 +391,6 @@ impl<'a, 'tcx> PermissionsCtxt<'a, 'tcx> {
       loan_read_refined,
       loan_write_refined,
       loan_drop_refined,
-      permissions,
     }
   }
 
@@ -446,7 +416,6 @@ impl<'a, 'tcx> PermissionsCtxt<'a, 'tcx> {
           loan_read_refined: None,
           loan_write_refined: None,
           loan_drop_refined: None,
-          permissions: Permissions::bottom(),
         })
       })
       .collect::<HashMap<_, _>>()
diff --git a/crates/aquascope/src/analysis/permissions/flow.rs b/crates/aquascope/src/analysis/permissions/flow.rs
index d67fe37f3..c7636d651 100644
--- a/crates/aquascope/src/analysis/permissions/flow.rs
+++ b/crates/aquascope/src/analysis/permissions/flow.rs
@@ -76,22 +76,23 @@
 use std::time::Instant;
 
 use itertools::Itertools;
-use rustc_borrowck::borrow_set::BorrowData;
+use rustc_borrowck::consumers::{
+  places_conflict, BorrowData, PlaceConflictBias, PoloniusRegionVid,
+};
 use rustc_data_structures::{
   fx::FxHashSet as HashSet,
-  graph::{
-    scc::Sccs, vec_graph::VecGraph, DirectedGraph, WithNumNodes, WithSuccessors,
-  },
+  graph::{depth_first_search, scc::Sccs, vec_graph::VecGraph, Successors},
   transitive_relation::{TransitiveRelation, TransitiveRelationBuilder},
 };
-use rustc_index::{bit_set::HybridBitSet, Idx};
-use rustc_utils::{mir::places_conflict, BodyExt};
+use rustc_index::{bit_set::ChunkedBitSet, Idx};
+use rustc_utils::BodyExt;
 use serde::Serialize;
 use ts_rs::TS;
 
 use super::{Origin, PermissionsCtxt};
 
 rustc_index::newtype_index! {
+  #[derive(Ord, PartialOrd)]
   #[debug_format = "scc{}"]
   pub struct SccIdx {}
 }
@@ -144,10 +145,10 @@ pub struct RegionFlows {
   specified_flows: TransitiveRelation<SccIdx>,
 
   /// Local regions that could dangle due to an exit invalidation.
-  dangling_local_sources: HybridBitSet<SccIdx>,
+  dangling_local_sources: ChunkedBitSet<SccIdx>,
 
   /// Regions that are equivalent to placeholders.
-  abstract_sources: HybridBitSet<SccIdx>,
+  abstract_sources: ChunkedBitSet<SccIdx>,
 
   /// The set of abstract components that a given component could contain.
   contains_abstract: TransitiveRelation<SccIdx>,
@@ -276,7 +277,7 @@ fn count_nodes<T: Idx>(tups: &[(T, T)]) -> usize {
 /// The return closure answers queries of the form "for (v, s) did `s` flow to v?"
 fn flow_from_sources<T>(
   sources: impl Iterator<Item = T>,
-  graph: impl DirectedGraph<Node = T> + WithSuccessors + WithNumNodes,
+  graph: impl Successors<Node = T>,
 ) -> TransitiveRelation<T>
 where
   T: Idx,
@@ -285,7 +286,7 @@ where
 
   // Compute the transitive closure, then assert that they're the same.
   for s in sources {
-    for t in graph.depth_first_search(s) {
+    for t in depth_first_search(&graph, s) {
       // `t` can point to `s`
       tcb.add(t, s);
     }
@@ -298,36 +299,29 @@ where
 ///
 /// Exit point would refer to a `StorageDead` or `Drop`.
 fn check_for_invalidation_at_exit<'tcx>(
-  ctxt: &PermissionsCtxt<'_, 'tcx>,
+  ctxt: &PermissionsCtxt<'tcx>,
   borrow: &BorrowData<'tcx>,
 ) -> bool {
-  use places_conflict::AccessDepth::{Deep, Shallow};
-  use rustc_middle::{
-    mir::{PlaceElem, PlaceRef, ProjectionElem},
-    ty::TyCtxt,
-  };
+  use rustc_middle::mir::{PlaceRef, ProjectionElem};
 
-  let place = borrow.borrowed_place;
+  let place = borrow.borrowed_place();
   let tcx = ctxt.tcx;
   let body = &ctxt.body_with_facts.body;
 
-  struct TyCtxtConsts<'tcx>(TyCtxt<'tcx>);
-  impl<'tcx> TyCtxtConsts<'tcx> {
-    const DEREF_PROJECTION: &'tcx [PlaceElem<'tcx>; 1] =
-      &[ProjectionElem::Deref];
-  }
-
   let mut root_place = PlaceRef {
     local: place.local,
     projection: &[],
   };
 
-  let (might_be_alive, will_be_dropped) =
+  // NOTE(2024-12-15, wcrichto): might_be_alive used to be used to determine
+  // AccessDepth, but changes to rustc API hid this parameter to make it always Deep.
+  // TBD if we need to request that to be re-exposed.
+  let (_might_be_alive, will_be_dropped) =
     if body.local_decls[root_place.local].is_ref_to_thread_local() {
       // Thread-locals might be dropped after the function exits
       // We have to dereference the outer reference because
       // borrows don't conflict behind shared references.
-      root_place.projection = TyCtxtConsts::DEREF_PROJECTION;
+      root_place.projection = &[ProjectionElem::Deref];
       (true, true)
     } else {
       (false, ctxt.locals_are_invalidated_at_exit)
@@ -341,16 +335,12 @@ fn check_for_invalidation_at_exit<'tcx>(
     return false;
   }
 
-  let sd = if might_be_alive { Deep } else { Shallow(None) };
-
-  places_conflict::borrow_conflicts_with_place(
+  places_conflict(
     tcx,
     body,
     place,
-    borrow.kind,
-    root_place,
-    sd,
-    places_conflict::PlaceConflictBias::Overlap,
+    root_place.to_place(tcx),
+    PlaceConflictBias::Overlap,
   )
 }
 
@@ -374,7 +364,8 @@ pub fn compute_flows(ctxt: &mut PermissionsCtxt) {
 
   // Graph of constraints that need to be satisfied. This shows
   // us how data flows from one region into another.
-  let constraint_graph = VecGraph::new(count_nodes(&constraints), constraints);
+  let constraint_graph =
+    VecGraph::<_, false>::new(count_nodes(&constraints), constraints);
 
   let scc_constraints = Sccs::<Origin, SccIdx>::new(&constraint_graph);
   let num_sccs = scc_constraints.num_sccs();
@@ -395,7 +386,11 @@ pub fn compute_flows(ctxt: &mut PermissionsCtxt) {
     .placeholder
     .iter()
     .filter_map(|&(p, _)| vertices.contains(&p).then_some(p))
-    .chain(body.regions_in_return().map(|rg| rg.as_var()))
+    .chain(
+      body
+        .regions_in_return()
+        .map(|rg| PoloniusRegionVid::from(rg.as_var())),
+    )
     .map(|p| scc_constraints.scc(p))
     .collect::<Vec<_>>();
 
@@ -418,7 +413,8 @@ pub fn compute_flows(ctxt: &mut PermissionsCtxt) {
   // Allowed flows between abstract regions specified in the type signature.
   //
   // e.g. `fn foo<'a, 'b: 'a>(...) ...` would cause a `'b: 'a` specified flow in this graph.
-  let specified_flows_graph = VecGraph::new(num_sccs, placeholder_edges);
+  let specified_flows_graph =
+    VecGraph::<_, false>::new(num_sccs, placeholder_edges);
 
   // Compute the flow facts between abstract regions.
   let specified_flows =
@@ -427,10 +423,10 @@ pub fn compute_flows(ctxt: &mut PermissionsCtxt) {
   // Compute local sources:
   // If `Place::is_indirect` returns false, the caller knows
   // that the Place refers to the same region of memory as its base.
-  let mut local_sources = HybridBitSet::new_empty(num_sccs);
-  for (_, bd) in ctxt.borrow_set.location_map.iter() {
-    if !bd.borrowed_place.is_indirect() {
-      let scc = scc_constraints.scc(bd.region);
+  let mut local_sources = ChunkedBitSet::new_empty(num_sccs);
+  for (_, bd) in ctxt.borrow_set.location_map().iter() {
+    if !bd.borrowed_place().is_indirect() {
+      let scc = scc_constraints.scc(PoloniusRegionVid::from(bd.region()));
       local_sources.insert(scc);
     }
   }
@@ -449,19 +445,19 @@ pub fn compute_flows(ctxt: &mut PermissionsCtxt) {
   let contains_local =
     flow_from_sources(local_sources.iter(), &scc_constraints);
 
-  let mut dangling_local_sources = HybridBitSet::new_empty(num_sccs);
+  let mut dangling_local_sources = ChunkedBitSet::new_empty(num_sccs);
 
   for (_, loans) in ctxt.polonius_output.errors.iter() {
     for &loan in loans.iter() {
       let bd = ctxt.loan_to_borrow(loan);
       if check_for_invalidation_at_exit(ctxt, bd) {
-        let scc = scc_constraints.scc(bd.region);
+        let scc = scc_constraints.scc(PoloniusRegionVid::from(bd.region()));
         dangling_local_sources.insert(scc);
       }
     }
   }
 
-  let mut abstract_sources = HybridBitSet::new_empty(num_sccs);
+  let mut abstract_sources = ChunkedBitSet::new_empty(num_sccs);
   for scc in placeholders.iter() {
     abstract_sources.insert(*scc);
   }
diff --git a/crates/aquascope/src/analysis/permissions/mod.rs b/crates/aquascope/src/analysis/permissions/mod.rs
index e0fde860f..1d6881451 100644
--- a/crates/aquascope/src/analysis/permissions/mod.rs
+++ b/crates/aquascope/src/analysis/permissions/mod.rs
@@ -38,6 +38,7 @@ impl polonius_engine::FactTypes for AquascopeFacts {
 }
 
 rustc_index::newtype_index! {
+  #[derive(PartialOrd, Ord)]
   #[debug_format = "path{}"]
   pub struct PathIndex {}
 }
@@ -112,9 +113,42 @@ pub struct PermissionsData {
   #[serde(skip_serializing_if = "Option::is_none")]
   /// Is a live loan removing `drop` permissions?
   pub loan_drop_refined: Option<LoanKey>,
+}
+
+impl PermissionsData {
+  /// If the place is not live, then the permissions are always the bottom type.
+  /// Otherwise, see `permissions_ignore_liveness`. (You may want to ignore liveness
+  /// when you know a variable is being used, and should therefore be live.)
+  pub fn permissions(&self) -> Permissions {
+    if self.is_live {
+      self.permissions_ignore_liveness()
+    } else {
+      Permissions::bottom()
+    }
+  }
 
-  /// Computed permissions given the above information.
-  pub permissions: Permissions,
+  /// A path is readable IFF:
+  /// - it is not moved.
+  /// - there doesn't exist a read-refining loan at this point.
+  ///
+  /// A path is writeable IFF:
+  /// - the path's declared type allows for mutability.
+  /// - the path is readable (you can't write if you can't read)
+  ///   this implies that the path isn't moved.
+  /// - there doesn't exist a write-refining loan at this point.
+  ///
+  /// A path is droppable(without copy) IFF:
+  /// - the path's declared type is droppable.
+  /// - it isn't moved.
+  /// - no drop-refining loan exists at this point.
+  pub fn permissions_ignore_liveness(&self) -> Permissions {
+    let mem_uninit = self.path_moved.is_some() || self.path_uninitialized;
+    let read = !mem_uninit && self.loan_read_refined.is_none();
+    let write =
+      self.type_writeable && read && self.loan_write_refined.is_none();
+    let drop = self.type_droppable && read && self.loan_drop_refined.is_none();
+    Permissions { read, write, drop }
+  }
 }
 
 /// A permissions refiner. [`Loan`]s and moves can refine permissions.
diff --git a/crates/aquascope/src/analysis/permissions/output.rs b/crates/aquascope/src/analysis/permissions/output.rs
index 78555585e..18e86ef39 100644
--- a/crates/aquascope/src/analysis/permissions/output.rs
+++ b/crates/aquascope/src/analysis/permissions/output.rs
@@ -10,19 +10,18 @@ use std::time::Instant;
 
 use datafrog::{Iteration, Relation, RelationLeaper, ValueFilter};
 use polonius_engine::{Algorithm, FactTypes, Output as PEOutput};
-use rustc_borrowck::{borrow_set::BorrowSet, consumers::BodyWithBorrowckFacts};
+use rustc_borrowck::consumers::{
+  places_conflict, BodyWithBorrowckFacts, BorrowSet, PlaceConflictBias,
+};
 use rustc_data_structures::fx::{FxHashMap as HashMap, FxHashSet as HashSet};
 use rustc_hir::{BodyId, Mutability};
 use rustc_index::IndexVec;
 use rustc_middle::{
   mir::{Place, ProjectionElem},
-  ty::TyCtxt,
+  ty::{TyCtxt, TypingEnv},
 };
 use rustc_mir_dataflow::move_paths::MoveData;
-use rustc_utils::{
-  mir::places_conflict::{self, AccessDepth, PlaceConflictBias},
-  BodyExt, PlaceExt,
-};
+use rustc_utils::{BodyExt, PlaceExt};
 
 use super::{
   context::PermissionsCtxt, flow, AquascopeFacts, Loan, Move, Path, Point,
@@ -321,7 +320,7 @@ pub fn derive_permission_facts(ctxt: &mut PermissionsCtxt) {
               p == point2 && {
                 let mp_assigned_to = ctxt.moveable_path_to_path(assigned_to);
                 let place1 = ctxt.path_to_place(mp_assigned_to);
-                places_conflict::places_conflict(
+                places_conflict(
                   tcx,
                   body,
                   place1,
@@ -392,13 +391,11 @@ pub fn derive_permission_facts(ctxt: &mut PermissionsCtxt) {
       |(_origin, loan, _point)| {
         let borrow = ctxt.loan_to_borrow(*loan);
         places.iter().filter_map(|place| {
-          places_conflict::borrow_conflicts_with_place(
+          places_conflict(
             tcx,
             body,
-            borrow.borrowed_place,
-            borrow.kind,
-            place.as_ref(),
-            AccessDepth::Deep,
+            borrow.borrowed_place(),
+            *place,
             PlaceConflictBias::Overlap,
           )
           .then_some((*loan, ctxt.place_to_path(place)))
@@ -497,11 +494,11 @@ pub fn derive_permission_facts(ctxt: &mut PermissionsCtxt) {
 // Main entry
 
 /// Compute the [`PermissionsCtxt`] for a given body.
-pub fn compute<'a, 'tcx>(
+pub fn compute<'tcx>(
   tcx: TyCtxt<'tcx>,
   body_id: BodyId,
-  body_with_facts: &'a BodyWithBorrowckFacts<'tcx>,
-) -> PermissionsCtxt<'a, 'tcx> {
+  body_with_facts: &'tcx BodyWithBorrowckFacts<'tcx>,
+) -> PermissionsCtxt<'tcx> {
   let timer = Instant::now();
   let def_id = tcx.hir().body_owner_def_id(body_id);
   let body = &body_with_facts.body;
@@ -520,23 +517,16 @@ pub fn compute<'a, 'tcx>(
 
   let locals_are_invalidated_at_exit =
     tcx.hir().body_owner_kind(def_id).is_fn_or_closure();
-  let move_data = match MoveData::gather_moves(body, tcx, tcx.param_env(def_id))
-  {
-    Ok(move_data) => move_data,
-    Err((move_data, _illegal_moves)) => {
-      log::debug!("illegal moves found {_illegal_moves:?}");
-      move_data
-    }
-  };
+  let move_data = MoveData::gather_moves(body, tcx, |_| true);
   let borrow_set =
     BorrowSet::build(tcx, body, locals_are_invalidated_at_exit, &move_data);
   let def_id = def_id.to_def_id();
-  let param_env = tcx.param_env_reveal_all_normalized(def_id);
+  let typing_env = TypingEnv::post_analysis(tcx, def_id);
 
   // This should always be true for the current analysis of aquascope
-  let locals_are_invalidated_at_exit = def_id.as_local().map_or(false, |did| {
-    tcx.hir().body_owner_kind(did).is_fn_or_closure()
-  });
+  let locals_are_invalidated_at_exit = def_id
+    .as_local()
+    .is_some_and(|did| tcx.hir().body_owner_kind(did).is_fn_or_closure());
 
   let mut ctxt = PermissionsCtxt {
     tcx,
@@ -549,7 +539,7 @@ pub fn compute<'a, 'tcx>(
     borrow_set,
     move_data,
     locals_are_invalidated_at_exit,
-    param_env,
+    typing_env,
     loan_regions: None,
     place_data: IndexVec::new(),
     rev_lookup: HashMap::default(),
diff --git a/crates/aquascope/src/analysis/permissions/utils.rs b/crates/aquascope/src/analysis/permissions/utils.rs
index ce032d7b6..2ea23e41e 100644
--- a/crates/aquascope/src/analysis/permissions/utils.rs
+++ b/crates/aquascope/src/analysis/permissions/utils.rs
@@ -2,48 +2,10 @@
 
 use std::collections::hash_map::Entry;
 
-use rustc_data_structures::fx::FxHashMap as HashMap;
-use rustc_middle::mir::{Location, TerminatorEdges};
-use rustc_mir_dataflow::{
-  fmt::DebugWithContext, Analysis, AnalysisDomain, JoinSemiLattice,
-};
-use rustc_utils::BodyExt;
+use rustc_middle::mir::pretty::PrettyPrintMirOptions;
+use rustc_mir_dataflow::{fmt::DebugWithContext, JoinSemiLattice};
 
-use super::{
-  context::PermissionsCtxt, Permissions, PermissionsData, PermissionsDomain,
-};
-
-pub(crate) fn dump_permissions_with_mir(ctxt: &PermissionsCtxt) {
-  // XXX: Unfortunately, the only way I know how to do this is to do a MIR
-  // dataflow analysis and simply take the information from the context.
-  // This mean there will only be a single pass but :shrug:
-
-  let def_id = ctxt.tcx.hir().body_owner_def_id(ctxt.body_id);
-
-  // Only print the analysis on a specific function
-  let owner = ctxt.tcx.hir().body_owner(ctxt.body_id);
-  let Some(name) = ctxt.tcx.hir().opt_name(owner) else {
-    return;
-  };
-  if name.as_str() != "dump_me" {
-    return;
-  }
-
-  let analysis = PAnalysis { ctxt };
-  let mut results = analysis
-    .into_engine(ctxt.tcx, &ctxt.body_with_facts.body)
-    .iterate_to_fixpoint();
-
-  log::debug!("Dumping results for {:?}", name.as_str());
-
-  if let Err(e) = ctxt.body_with_facts.body.write_analysis_results(
-    &mut results,
-    def_id.to_def_id(),
-    ctxt.tcx,
-  ) {
-    log::warn!("{:?}", e);
-  }
-}
+use super::{context::PermissionsCtxt, Permissions, PermissionsDomain};
 
 pub(crate) fn dump_mir_debug(ctxt: &PermissionsCtxt) {
   let tcx = ctxt.tcx;
@@ -56,8 +18,13 @@ pub(crate) fn dump_mir_debug(ctxt: &PermissionsCtxt) {
     body,
     &mut |_, _| Ok(()),
     &mut stderr,
+    PrettyPrintMirOptions {
+      include_extra_comments: false,
+    },
   )
   .unwrap();
+
+  log::debug!("{:?}", ctxt.polonius_output);
 }
 
 // --------------------------------------------------
@@ -97,7 +64,7 @@ impl JoinSemiLattice for PermissionsDomain<'_> {
     for (place, perms) in other.0.iter() {
       match self.0.entry(*place) {
         Entry::Occupied(mut entry) => {
-          changed |= entry.get_mut().permissions.join(&perms.permissions);
+          changed |= entry.get_mut().permissions().join(&perms.permissions());
         }
         Entry::Vacant(entry) => {
           entry.insert(*perms);
@@ -149,7 +116,7 @@ impl<C> DebugWithContext<C> for PermissionsDomain<'_> {
       r#"<table border="0" cellborder="1" cellspacing="0" cellpadding="2">"#
     )?;
     for (place, perms) in self.iter() {
-      let perms = perms.permissions;
+      let perms = perms.permissions();
       write!(
         f,
         r#"<tr><td align="left">{place:?}</td><td align="left">{perms:?}</td></tr>"#
@@ -167,11 +134,11 @@ impl<C> DebugWithContext<C> for PermissionsDomain<'_> {
     f: &mut std::fmt::Formatter<'_>,
   ) -> std::fmt::Result {
     let no_perm_changes = self.0.iter().all(|(place, permsd)| {
-      let perms = permsd.permissions;
+      let perms = permsd.permissions();
       old
         .0
         .get(place)
-        .map_or(true, |permd| permd.permissions == perms)
+        .is_none_or(|permd| permd.permissions() == perms)
     });
 
     if old == self || no_perm_changes {
@@ -183,10 +150,10 @@ impl<C> DebugWithContext<C> for PermissionsDomain<'_> {
       r#"<table border="0" cellborder="1" cellspacing="0" cellpadding="2" sides="rb">"#
     )?;
     for (place, perms) in self.0.iter() {
-      let perms = perms.permissions;
+      let perms = perms.permissions();
       match old.0.get(place) {
         Some(old_perms) => {
-          let old_perms = old_perms.permissions;
+          let old_perms = old_perms.permissions();
           if perms != old_perms {
             write!(
               f,
@@ -208,96 +175,3 @@ impl<C> DebugWithContext<C> for PermissionsDomain<'_> {
     Ok(())
   }
 }
-
-// --------------------------------------------------
-// Analysis
-
-pub(crate) struct PAnalysis<'a, 'tcx> {
-  ctxt: &'a PermissionsCtxt<'a, 'tcx>,
-}
-
-impl<'a, 'tcx> PAnalysis<'a, 'tcx> {
-  fn check_location(
-    &self,
-    state: &mut PermissionsDomain<'tcx>,
-    location: Location,
-  ) {
-    let point = self.ctxt.location_to_point(location);
-    let dmn = self.ctxt.permissions_domain_at_point(point);
-    for (place, perms) in state.iter_mut() {
-      let new_perms = dmn.get(place).unwrap();
-      *perms = *new_perms;
-    }
-  }
-}
-
-impl<'tcx> AnalysisDomain<'tcx> for PAnalysis<'_, 'tcx> {
-  type Domain = PermissionsDomain<'tcx>;
-  const NAME: &'static str = "PermissionsAnalysisDatalog";
-
-  fn bottom_value(
-    &self,
-    _body: &rustc_middle::mir::Body<'tcx>,
-  ) -> Self::Domain {
-    self
-      .ctxt
-      .domain_places()
-      .into_iter()
-      .map(|place| {
-        let path = self.ctxt.place_to_path(&place);
-        let mp = self.ctxt.max_permissions(path);
-        // NOTE: I'm currently just ignoring the permissions data
-        // for this utility just so we can see the permissions changes.
-        (place, PermissionsData {
-          is_live: false,
-          type_droppable: false,
-          type_writeable: false,
-          type_copyable: false,
-          path_moved: None,
-          path_uninitialized: false,
-          loan_read_refined: None,
-          loan_write_refined: None,
-          loan_drop_refined: None,
-          permissions: mp,
-        })
-      })
-      .collect::<HashMap<_, _>>()
-      .into()
-  }
-
-  fn initialize_start_block(
-    &self,
-    _body: &rustc_middle::mir::Body<'tcx>,
-    _state: &mut Self::Domain,
-  ) {
-  }
-}
-
-impl<'tcx> Analysis<'tcx> for PAnalysis<'_, 'tcx> {
-  fn apply_statement_effect(
-    &mut self,
-    state: &mut Self::Domain,
-    _statement: &rustc_middle::mir::Statement<'tcx>,
-    location: rustc_middle::mir::Location,
-  ) {
-    self.check_location(state, location);
-  }
-
-  fn apply_terminator_effect<'mir>(
-    &mut self,
-    state: &mut Self::Domain,
-    terminator: &'mir rustc_middle::mir::Terminator<'tcx>,
-    location: rustc_middle::mir::Location,
-  ) -> TerminatorEdges<'mir, 'tcx> {
-    self.check_location(state, location);
-    terminator.edges()
-  }
-
-  fn apply_call_return_effect(
-    &mut self,
-    _state: &mut Self::Domain,
-    _block: rustc_middle::mir::BasicBlock,
-    _return_places: rustc_middle::mir::CallReturnPlaces<'_, 'tcx>,
-  ) {
-  }
-}
diff --git a/crates/aquascope/src/analysis/stepper/hir_steps.rs b/crates/aquascope/src/analysis/stepper/hir_steps.rs
index 7d59a226a..4db84e972 100644
--- a/crates/aquascope/src/analysis/stepper/hir_steps.rs
+++ b/crates/aquascope/src/analysis/stepper/hir_steps.rs
@@ -81,10 +81,10 @@ pub(super) struct HirStepPoints<'a, 'tcx>
 where
   'tcx: 'a,
 {
-  tcx: &'a TyCtxt<'tcx>,
-  body: &'a Body<'tcx>,
+  tcx: TyCtxt<'tcx>,
+  body: &'tcx Body<'tcx>,
   body_id: BodyId,
-  ir_mapper: &'a IRMapper<'a, 'tcx>,
+  ir_mapper: &'a IRMapper<'tcx>,
 
   // Error reporting counters
   unsupported_features: Vec<anyhow::Error>,
@@ -145,10 +145,10 @@ macro_rules! report_unsupported {
 
 impl<'a, 'tcx: 'a> HirStepPoints<'a, 'tcx> {
   pub(super) fn make(
-    tcx: &'a TyCtxt<'tcx>,
-    body: &'a Body<'tcx>,
+    tcx: TyCtxt<'tcx>,
+    body: &'tcx Body<'tcx>,
     body_id: BodyId,
-    ir_mapper: &'a IRMapper<'a, 'tcx>,
+    ir_mapper: &'a IRMapper<'tcx>,
   ) -> Result<Self> {
     let mir_segments = SegmentedMirBuilder::make(ir_mapper);
     let start_loc = mir::START_BLOCK.start_location();
@@ -191,7 +191,7 @@ impl<'a, 'tcx: 'a> HirStepPoints<'a, 'tcx> {
 
   pub(super) fn finalize(
     self,
-    analysis: &AquascopeAnalysis<'_, 'tcx>,
+    analysis: &AquascopeAnalysis<'tcx>,
     mode: PermIncludeMode,
   ) -> Result<Vec<PermissionsLineDisplay>> {
     let body_hir_id = self.body_value_id();
@@ -225,8 +225,13 @@ impl<'a, 'tcx: 'a> HirStepPoints<'a, 'tcx> {
   }
 
   fn pop_branch_start(&mut self, expecting: Location) {
-    if let Some(popped) = self.current_branch_start.pop() && popped != expecting {
-      report_unexpected!(self, "expecting popped location {expecting:?} but got {popped:?}")
+    if let Some(popped) = self.current_branch_start.pop()
+      && popped != expecting
+    {
+      report_unexpected!(
+        self,
+        "expecting popped location {expecting:?} but got {popped:?}"
+      )
     }
   }
 
@@ -487,12 +492,12 @@ impl<'a, 'tcx: 'a> HirVisitor<'tcx> for HirStepPoints<'a, 'tcx> {
     self.tcx.hir()
   }
 
-  fn visit_body(&mut self, body: &'tcx hir::Body) {
+  fn visit_body(&mut self, body: &hir::Body<'tcx>) {
     intravisit::walk_body(self, body);
     self.insert_step_at_node_exit(body.value.hir_id);
   }
 
-  fn visit_block(&mut self, block: &'tcx hir::Block) {
+  fn visit_block(&mut self, block: &hir::Block<'tcx>) {
     let scope = invoke_internal!(self, open_scope);
     for stmt in block.stmts.iter() {
       self.visit_stmt(stmt);
@@ -507,7 +512,7 @@ impl<'a, 'tcx: 'a> HirVisitor<'tcx> for HirStepPoints<'a, 'tcx> {
     invoke_internal!(self, close_scope, scope);
   }
 
-  fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt) {
+  fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt<'tcx>) {
     use rustc_hir::StmtKind as SK;
 
     log::debug!(
@@ -517,7 +522,8 @@ impl<'a, 'tcx: 'a> HirVisitor<'tcx> for HirStepPoints<'a, 'tcx> {
 
     let scope = invoke_internal!(self, open_scope);
 
-    if let SK::Local(local) = stmt.kind {
+    // TODO(gavin): fixme or deleteme
+    if let SK::Let(local) = stmt.kind {
       let places = self.ir_mapper.local_assigned_place(local);
       let locals = places.into_iter().map(|p| p.local).collect::<Vec<_>>();
       if !locals.is_empty() {
@@ -549,8 +555,10 @@ impl<'a, 'tcx: 'a> HirVisitor<'tcx> for HirStepPoints<'a, 'tcx> {
         }
 
         // Insert the location and span for the else branch
-        if let Some(els) = else_opt && let Some(else_entry) = self.get_node_entry(els.hir_id) {
-        let else_span = self.span_of(els.hir_id).shrink_to_lo();
+        if let Some(els) = else_opt
+          && let Some(else_entry) = self.get_node_entry(els.hir_id)
+        {
+          let else_span = self.span_of(els.hir_id).shrink_to_lo();
           entry_to_spans.insert(else_entry, else_span);
         }
 
@@ -782,7 +790,7 @@ mod tests {
         let body = &wfacts.body;
         let mapper = IRMapper::new(tcx, body, GatherMode::IgnoreCleanup);
 
-        let mut visitor = HirStepPoints::make(&tcx, body, body_id, &mapper)
+        let mut visitor = HirStepPoints::make(tcx, body, body_id, &mapper)
           .expect("Failed to create stepper");
         visitor.visit_nested_body(body_id);
 
@@ -1102,7 +1110,6 @@ fn punch_card() -> impl std::fmt::Debug {
   );
 
   test_valid_segmented_mir!(
-    panics_with "invalid smir" =>
     weird_exprs_i_yield,
     r#"
 #![feature(generators)]
@@ -1185,7 +1192,11 @@ fn bathroom_stall() {
 "#
   );
 
+  // TODO(gavin) what changed in MIR output that causes the
+  // dominator analysis to fail...
+  // Real error message "no open collection dominates bb6[3]"
   test_valid_segmented_mir!(
+    panics_with "internal error" =>
     weird_exprs_closure_matching,
     r#"
 fn closure_matching() {
diff --git a/crates/aquascope/src/analysis/stepper/mod.rs b/crates/aquascope/src/analysis/stepper/mod.rs
index 387842295..a796d51f6 100644
--- a/crates/aquascope/src/analysis/stepper/mod.rs
+++ b/crates/aquascope/src/analysis/stepper/mod.rs
@@ -266,7 +266,7 @@ impl Difference for PermissionsData {
       loan_drop_refined: self.loan_drop_refined.diff(rhs.loan_drop_refined),
       path_moved: self.path_moved.diff(rhs.path_moved),
       path_uninitialized: self.path_uninitialized.diff(rhs.path_uninitialized),
-      permissions: self.permissions.diff(rhs.permissions),
+      permissions: self.permissions().diff(rhs.permissions()),
     }
   }
 }
@@ -319,12 +319,13 @@ impl MirSegment {
   pub fn span(&self, ctxt: &PermissionsCtxt) -> Span {
     let lo = ctxt.location_to_span(self.from);
     let hi = ctxt.location_to_span(self.to);
+    log::debug!("Span for segment {self:?}: {:?} -> {:?}", lo, hi);
     lo.with_hi(hi.hi())
   }
 
   pub fn into_diff<'tcx>(
     self,
-    ctxt: &PermissionsCtxt<'_, 'tcx>,
+    ctxt: &PermissionsCtxt<'tcx>,
   ) -> HashMap<Place<'tcx>, PermissionsDataDiff> {
     let p0 = ctxt.location_to_point(self.from);
     let p1 = ctxt.location_to_point(self.to);
@@ -337,18 +338,15 @@ impl MirSegment {
 // ----------
 // Main entry
 
-pub fn compute_permission_steps<'a, 'tcx>(
-  analysis: &AquascopeAnalysis<'a, 'tcx>,
-) -> Result<Vec<PermissionsLineDisplay>>
-where
-  'tcx: 'a,
-{
+pub fn compute_permission_steps(
+  analysis: &AquascopeAnalysis<'_>,
+) -> Result<Vec<PermissionsLineDisplay>> {
   let mode = INCLUDE_MODE.copied().unwrap_or(PermIncludeMode::Changes);
   let ctxt = &analysis.permissions;
   let ir_mapper = &analysis.ir_mapper;
   let body = &ctxt.body_with_facts.body;
   let mut hir_visitor =
-    hir_steps::HirStepPoints::make(&ctxt.tcx, body, ctxt.body_id, ir_mapper)?;
+    hir_steps::HirStepPoints::make(ctxt.tcx, body, ctxt.body_id, ir_mapper)?;
 
   hir_visitor.visit_nested_body(ctxt.body_id);
 
diff --git a/crates/aquascope/src/analysis/stepper/segmented_mir.rs b/crates/aquascope/src/analysis/stepper/segmented_mir.rs
index 6176de93d..05d01da37 100644
--- a/crates/aquascope/src/analysis/stepper/segmented_mir.rs
+++ b/crates/aquascope/src/analysis/stepper/segmented_mir.rs
@@ -216,7 +216,7 @@ type BranchSpannerMap<'a> =
   HashMap<BranchId, Box<dyn Fn(&mut Location) -> Span + 'a>>;
 
 pub(super) struct SegmentedMirBuilder<'a, 'tcx: 'a> {
-  mapper: &'a IRMapper<'a, 'tcx>,
+  mapper: &'a IRMapper<'tcx>,
   first_collection: CollectionId,
   root_mappings: BranchSpannerMap<'a>,
   collections: IndexVec<CollectionId, Collection>,
@@ -356,7 +356,7 @@ enum GetSpanner<'a> {
 }
 
 impl<'a, 'tcx: 'a> SegmentedMirBuilder<'a, 'tcx> {
-  pub fn make(mapper: &'a IRMapper<'a, 'tcx>) -> Self {
+  pub fn make(mapper: &'a IRMapper<'tcx>) -> Self {
     let from = mapper.cleaned_graph.start_node().start_location();
 
     let mut collections = IndexVec::new();
@@ -471,18 +471,20 @@ impl<'a, 'tcx: 'a> SegmentedMirBuilder<'a, 'tcx> {
     let mapper = &self.mapper;
 
     // Find all basic blocks that are reachable from the root.
-    let reachable = mapper
-      .cleaned_graph
-      .depth_first_search(root)
+    let reachable = depth_first_search(&mapper.cleaned_graph, root)
       .filter(|&to| mapper.dominates(root, to))
       .collect::<HashSet<_>>();
 
+    log::debug!("Reachable from root: {reachable:?}");
+
     // Find the blocks that is the _most_ post-dominating,
     // this is a point that must post-dominate everything else.
     let most_post_dominating = reachable
       .iter()
       .find(|&can| reachable.iter().all(|&n| mapper.post_dominates(*can, n)))?;
 
+    log::debug!("Most post-dominating: {most_post_dominating:?}");
+
     // If a block dominates the "most post-dominator" that means that this
     // block also post-dominates all branches that occur after the root.
     // We exclude the (1) root itself, and (2) any false edges. False edges
@@ -497,6 +499,8 @@ impl<'a, 'tcx: 'a> SegmentedMirBuilder<'a, 'tcx> {
       })
       .collect::<Vec<_>>();
 
+    log::debug!("Candidate least-dominating: {candidate_leasts:?}");
+
     // The least post-dominator dominates all the other post-dominators.
     candidate_leasts
       .iter()
@@ -868,6 +872,7 @@ pub(crate) mod test_exts {
     fn validate(&self, mapper: &IRMapper) -> Result<(), InvalidReason>;
   }
 
+  #[allow(dead_code)]
   #[derive(Debug)]
   pub enum InvalidReason {
     MissingLocations {
@@ -909,7 +914,7 @@ pub(crate) mod test_exts {
   impl MirSegment {
     fn explode<'a, 'tcx: 'a>(
       self,
-      mapper: &'a IRMapper<'a, 'tcx>,
+      mapper: &'a IRMapper<'tcx>,
     ) -> impl Iterator<Item = Location> + Captures<'tcx> + 'a {
       let sb = self.from.block;
       let eb = self.to.block;
diff --git a/crates/aquascope/src/analysis/stepper/table_builder.rs b/crates/aquascope/src/analysis/stepper/table_builder.rs
index c65b685d5..b88b4c781 100644
--- a/crates/aquascope/src/analysis/stepper/table_builder.rs
+++ b/crates/aquascope/src/analysis/stepper/table_builder.rs
@@ -30,8 +30,8 @@ pub(super) struct Table<'tcx> {
 pub(super) type Tables<'tcx> = HashMap<Location, Vec<Table<'tcx>>>;
 
 pub(super) struct TableBuilder<'a, 'tcx: 'a> {
-  pub(super) analysis: &'a AquascopeAnalysis<'a, 'tcx>,
-  pub(super) ctxt: &'a PermissionsCtxt<'a, 'tcx>,
+  pub(super) analysis: &'a AquascopeAnalysis<'tcx>,
+  pub(super) ctxt: &'a PermissionsCtxt<'tcx>,
   pub(super) mir: &'a SegmentedMir,
   pub(super) locals_at_scope: HashMap<ScopeId, Vec<Local>>,
 }
@@ -145,7 +145,6 @@ impl<'a, 'tcx: 'a> TableBuilder<'a, 'tcx> {
     let BranchData {
       reach,
       splits,
-      // joins,
       nested,
       ..
     } = self.mir.get_branch(bid);
@@ -160,8 +159,6 @@ impl<'a, 'tcx: 'a> TableBuilder<'a, 'tcx> {
     );
 
     let mut temp_middle = Tables::default();
-    // let mut temp_joins = Tables::default();
-
     for &sid in splits.iter() {
       self.insert_segment(&mut temp_middle, sid);
     }
@@ -170,10 +167,6 @@ impl<'a, 'tcx: 'a> TableBuilder<'a, 'tcx> {
       self.insert_collection(&mut temp_middle, cid);
     }
 
-    // for &sid in joins.iter() {
-    //   self.insert_segment(&mut temp_joins, sid);
-    // }
-
     // Find the locals which were filtered from all scopes. In theory,
     // `all_scopes` should contains the same scope, copied over,
     // but the SegmentedMir doesn't enforce this and there's no
@@ -209,7 +202,7 @@ impl<'a, 'tcx: 'a> TableBuilder<'a, 'tcx> {
 // - Convert Spans to Ranges
 #[allow(clippy::if_not_else)]
 pub(super) fn prettify_permission_steps<'tcx>(
-  analysis: &AquascopeAnalysis<'_, 'tcx>,
+  analysis: &AquascopeAnalysis<'tcx>,
   perm_steps: Tables<'tcx>,
   mode: PermIncludeMode,
 ) -> Vec<PermissionsLineDisplay> {
@@ -361,7 +354,7 @@ pub(super) fn prettify_permission_steps<'tcx>(
         .collect::<Vec<_>>();
 
       master_table_vec
-            .sort_by_key(|(place, _)| (place.local.as_usize(), place.projection));
+            .sort_by_key(|(place, _)| (place.local.as_usize(), place.projection.len()));
 
       let master_table = PermissionsStepTable {
         from,
diff --git a/crates/aquascope/src/bin/export-ts.rs b/crates/aquascope/src/bin/export-ts.rs
index 7c9ffc805..331ac24f8 100644
--- a/crates/aquascope/src/bin/export-ts.rs
+++ b/crates/aquascope/src/bin/export-ts.rs
@@ -1,3 +1,5 @@
+#![feature(rustc_private)]
+
 use rustc_utils::source_map::{
   filename::FilenameIndex,
   range::{CharPos, CharRange},
diff --git a/crates/aquascope/src/errors/mod.rs b/crates/aquascope/src/errors/mod.rs
index 068291ee5..77fd0f93a 100644
--- a/crates/aquascope/src/errors/mod.rs
+++ b/crates/aquascope/src/errors/mod.rs
@@ -1,14 +1,14 @@
-pub(crate) mod silent_emitter;
+pub mod silent;
 
 use std::cell::RefCell;
 
-use rustc_errors::{Diagnostic, TRACK_DIAGNOSTICS};
+use rustc_errors::{DiagInner, TRACK_DIAGNOSTIC};
 use rustc_hir::def_id::LocalDefId;
 use rustc_span::Span;
 
 thread_local! {
     static BODY_DIAGNOSTICS: RefCell<Vec<DiagnosticInfo>> = RefCell::new(Vec::default());
-    static CURRENT_BODY: RefCell<Option<LocalDefId>> = RefCell::new(None);
+    static CURRENT_BODY: RefCell<Option<LocalDefId>> = const { RefCell::new(None) };
 }
 
 #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
@@ -17,7 +17,7 @@ struct DiagnosticInfo {
   is_error: bool,
 }
 
-fn track_diagnostic(d: &mut Diagnostic, f: &mut dyn FnMut(&mut Diagnostic)) {
+fn track_diagnostic<R>(d: DiagInner, f: &mut dyn FnMut(DiagInner) -> R) -> R {
   BODY_DIAGNOSTICS.with(|diagnostics| {
     let mut diagnostics = diagnostics.borrow_mut();
     let d = DiagnosticInfo {
@@ -30,7 +30,7 @@ fn track_diagnostic(d: &mut Diagnostic, f: &mut dyn FnMut(&mut Diagnostic)) {
   // We need to actually report the diagnostic with the
   // provided function. Otherwise, a `DelayedBugPanic`
   // will cause an ICE.
-  (*f)(d);
+  (*f)(d)
 }
 
 // ------------------------------------------------
@@ -39,7 +39,7 @@ fn track_diagnostic(d: &mut Diagnostic, f: &mut dyn FnMut(&mut Diagnostic)) {
 /// This should be called before analysing a new crate.
 pub fn initialize_error_tracking() {
   log::debug!("Track diagnostics updated");
-  TRACK_DIAGNOSTICS.swap(&(track_diagnostic as _));
+  TRACK_DIAGNOSTIC.swap(&(track_diagnostic as _));
 }
 
 /// Initialize the error tracking for a given routine. It's recommended
diff --git a/crates/aquascope/src/errors/silent.rs b/crates/aquascope/src/errors/silent.rs
new file mode 100644
index 000000000..0467b91dc
--- /dev/null
+++ b/crates/aquascope/src/errors/silent.rs
@@ -0,0 +1,11 @@
+use rustc_driver::DEFAULT_LOCALE_RESOURCES;
+use rustc_errors::fallback_fluent_bundle;
+use rustc_session::parse::ParseSess;
+
+pub fn silent_session() -> Box<dyn FnOnce(&mut ParseSess) + Send> {
+  Box::new(|sess| {
+    let fallback_bundle =
+      fallback_fluent_bundle(DEFAULT_LOCALE_RESOURCES.to_vec(), false);
+    sess.dcx().make_silent(fallback_bundle, None, false);
+  })
+}
diff --git a/crates/aquascope/src/errors/silent_emitter.rs b/crates/aquascope/src/errors/silent_emitter.rs
deleted file mode 100644
index 010708f6f..000000000
--- a/crates/aquascope/src/errors/silent_emitter.rs
+++ /dev/null
@@ -1,29 +0,0 @@
-//! Silent diagnostics emitter.
-//!
-//! See:
-//! https://doc.rust-lang.org/nightly/nightly-rustc/rustfmt_nightly/parse/session/struct.SilentEmitter.html#impl-Translate-for-SilentEmitter
-
-use rustc_data_structures::sync::Lrc;
-use rustc_errors::{emitter::Emitter, translation::Translate, Diagnostic};
-use rustc_span::source_map::SourceMap;
-
-/// Emitter which discards every error.
-pub(crate) struct SilentEmitter;
-
-impl Translate for SilentEmitter {
-  fn fluent_bundle(&self) -> Option<&Lrc<rustc_errors::FluentBundle>> {
-    None
-  }
-
-  fn fallback_fluent_bundle(&self) -> &rustc_errors::FluentBundle {
-    panic!("silent emitter attempted to translate a diagnostic");
-  }
-}
-
-impl Emitter for SilentEmitter {
-  fn source_map(&self) -> Option<&Lrc<SourceMap>> {
-    None
-  }
-
-  fn emit_diagnostic(&mut self, _db: &Diagnostic) {}
-}
diff --git a/crates/aquascope/src/interpreter/mapper.rs b/crates/aquascope/src/interpreter/mapper.rs
index 99b670c99..de88867dd 100644
--- a/crates/aquascope/src/interpreter/mapper.rs
+++ b/crates/aquascope/src/interpreter/mapper.rs
@@ -9,7 +9,7 @@ use either::Either;
 use itertools::Itertools;
 use miri::InterpCx;
 use rustc_hir::{intravisit::Visitor, Body, Expr, ExprKind, HirId, Stmt};
-use rustc_middle::{mir::Location, ty::InstanceDef};
+use rustc_middle::{mir::Location, ty::Instance};
 use rustc_span::{BytePos, Span};
 use rustc_utils::BodyExt;
 
@@ -45,29 +45,27 @@ struct MapperEntry {
   body_mapping: HashMap<Location, HirId>,
 }
 
-pub struct Mapper<'a, 'mir, 'tcx> {
-  ecx: &'a InterpCx<'mir, 'tcx, miri::MiriMachine<'mir, 'tcx>>,
-  mapping: RefCell<HashMap<InstanceDef<'tcx>, MapperEntry>>,
+pub struct Mapper<'a, 'tcx> {
+  ecx: &'a InterpCx<'tcx, miri::MiriMachine<'tcx>>,
+  mapping: RefCell<HashMap<Instance<'tcx>, MapperEntry>>,
 }
 
-impl<'a, 'mir, 'tcx> Mapper<'a, 'mir, 'tcx> {
-  pub fn new(
-    ecx: &'a InterpCx<'mir, 'tcx, miri::MiriMachine<'mir, 'tcx>>,
-  ) -> Self {
+impl<'a, 'tcx> Mapper<'a, 'tcx> {
+  pub fn new(ecx: &'a InterpCx<'tcx, miri::MiriMachine<'tcx>>) -> Self {
     Mapper {
       ecx,
       mapping: RefCell::default(),
     }
   }
 
-  fn build_body_mapping(&self, inst: InstanceDef<'tcx>) -> MapperEntry {
+  fn build_body_mapping(&self, inst: Instance<'tcx>) -> MapperEntry {
     let mut finder = FindSteppableNodes::default();
     let tcx = *self.ecx.tcx;
     let hir = tcx.hir();
-    let body_id = hir.body_owned_by(inst.def_id().expect_local());
-    finder.visit_body(hir.body(body_id));
+    let hir_body = hir.body_owned_by(inst.def_id().expect_local());
+    finder.visit_body(hir_body);
 
-    let body = self.ecx.load_mir(inst, None).unwrap();
+    let body = self.ecx.load_mir(inst.def, None).unwrap();
     log::debug!("{}", body.to_string(tcx).unwrap());
     let mapper = IRMapper::new(tcx, body, GatherMode::All);
 
@@ -88,7 +86,7 @@ impl<'a, 'mir, 'tcx> Mapper<'a, 'mir, 'tcx> {
       .collect();
 
     MapperEntry {
-      owner_id: hir.body_owner(body_id),
+      owner_id: hir.body_owner(hir_body.id()),
       body_mapping,
     }
   }
@@ -96,12 +94,12 @@ impl<'a, 'mir, 'tcx> Mapper<'a, 'mir, 'tcx> {
   fn is_cleanup(
     &self,
     owner_id: HirId,
-    inst: InstanceDef<'tcx>,
+    inst: Instance<'tcx>,
     location: Location,
   ) -> Option<Span> {
     let body_span = self.ecx.tcx.hir().span_with_body(owner_id);
     let end_brace = body_span.with_lo(body_span.hi() - BytePos(1));
-    let body = self.ecx.load_mir(inst, None).unwrap();
+    let body = self.ecx.load_mir(inst.def, None).unwrap();
     let loc_span = body.source_info(location).span;
     (loc_span == end_brace).then_some(end_brace)
   }
diff --git a/crates/aquascope/src/interpreter/miri_utils.rs b/crates/aquascope/src/interpreter/miri_utils.rs
index f58a18edb..12078dae0 100644
--- a/crates/aquascope/src/interpreter/miri_utils.rs
+++ b/crates/aquascope/src/interpreter/miri_utils.rs
@@ -1,6 +1,6 @@
 use miri::{
-  interpret::Provenance, InterpCx, InterpResult, MPlaceTy, Machine,
-  MemPlaceMeta, OpTy,
+  interp_ok, InterpCx, InterpResult, MPlaceTy, Machine, MemPlaceMeta, OpTy,
+  Projectable,
 };
 use rustc_abi::FieldsShape;
 use rustc_middle::{
@@ -9,24 +9,23 @@ use rustc_middle::{
 };
 use rustc_target::abi::{FieldIdx, Size};
 
-pub trait OpTyExt<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>>: Sized {
+pub trait OpTyExt<'tcx, M: Machine<'tcx>>: Sized {
   fn field_by_name(
     &self,
     name: &str,
-    ecx: &InterpCx<'mir, 'tcx, M>,
+    ecx: &InterpCx<'tcx, M>,
   ) -> InterpResult<'tcx, (&FieldDef, Self)>;
 }
 
-impl<'mir, 'tcx, M, Prov: Provenance + 'static> OpTyExt<'mir, 'tcx, M>
-  for OpTy<'tcx, Prov>
+impl<'tcx, M> OpTyExt<'tcx, M> for OpTy<'tcx>
 where
-  M: Machine<'mir, 'tcx, Provenance = Prov>,
-  'tcx: 'mir,
+  M: Machine<'tcx>,
+  Self: Projectable<'tcx, M::Provenance>,
 {
   fn field_by_name(
     &self,
     name: &str,
-    ecx: &InterpCx<'mir, 'tcx, M>,
+    ecx: &InterpCx<'tcx, M>,
   ) -> InterpResult<'tcx, (&FieldDef, Self)> {
     let adt_def = self.layout.ty.ty_adt_def().unwrap();
     let (i, field) = adt_def
@@ -42,17 +41,18 @@ where
             .collect::<Vec<_>>()
         )
       });
-    Ok((field, ecx.project_field(self, i)?))
+    let field_op = ecx.project_field(self, i)?;
+    interp_ok((field, field_op))
   }
 }
 
-struct AddressLocator<'a, 'mir, 'tcx> {
-  ecx: &'a InterpCx<'mir, 'tcx, miri::MiriMachine<'mir, 'tcx>>,
+struct AddressLocator<'a, 'tcx> {
+  ecx: &'a InterpCx<'tcx, miri::MiriMachine<'tcx>>,
   target: u64,
   segments: Vec<PlaceElem<'tcx>>,
 }
 
-impl<'tcx> AddressLocator<'_, '_, 'tcx> {
+impl<'tcx> AddressLocator<'_, 'tcx> {
   fn locate(&mut self, layout: TyAndLayout<'tcx>, mut offset: u64) {
     if offset == self.target {
       return;
@@ -127,11 +127,11 @@ impl<'tcx> AddressLocator<'_, '_, 'tcx> {
   }
 }
 
-pub fn locate_address_in_type<'mir, 'tcx>(
-  ecx: &InterpCx<'mir, 'tcx, miri::MiriMachine<'mir, 'tcx>>,
+pub fn locate_address_in_type<'tcx>(
+  ecx: &InterpCx<'tcx, miri::MiriMachine<'tcx>>,
   alloc_layout: TyAndLayout<'tcx>,
   alloc_size: Size,
-  mplace: MPlaceTy<'tcx, miri::Provenance>,
+  mplace: MPlaceTy<'tcx>,
   target: Size,
 ) -> Vec<PlaceElem<'tcx>> {
   // dbg!((alloc_layout, alloc_size, mplace, target));
@@ -153,7 +153,7 @@ pub fn locate_address_in_type<'mir, 'tcx>(
     let index = offset / array_elem_size;
     // dbg!((array_elem_size, offset, index));
 
-    let segment = match mplace.meta {
+    let segment = match mplace.meta() {
       MemPlaceMeta::Meta(meta) => {
         let end_offset = meta.to_u64().unwrap();
         let to = index + end_offset / array_elem_size - 1;
diff --git a/crates/aquascope/src/interpreter/mod.rs b/crates/aquascope/src/interpreter/mod.rs
index 02dad325d..45e18cd0e 100644
--- a/crates/aquascope/src/interpreter/mod.rs
+++ b/crates/aquascope/src/interpreter/mod.rs
@@ -6,8 +6,8 @@ use rustc_data_structures::fx::FxIndexMap;
 use rustc_hir::def_id::LocalDefId;
 use rustc_middle::{
   mir::{Body, BorrowCheckResult},
-  query,
   ty::TyCtxt,
+  util::Providers,
 };
 use rustc_utils::{source_map::range::CharRange, SpanExt};
 
@@ -32,7 +32,7 @@ pub(crate) fn interpret(tcx: TyCtxt) -> Result<MTrace<CharRange>> {
       let (inst, mir_body_loc) = step.stack.frames.last().unwrap().location;
       log::trace!("{}", match mir_body_loc {
         Either::Left(loc) => {
-          let body = evaluator.ecx.load_mir(inst, None).unwrap();
+          let body = evaluator.ecx.load_mir(inst.def, None).unwrap();
           format!("{:?}", body.stmt_at(loc))
         }
         Either::Right(span) =>
@@ -101,18 +101,17 @@ fn fake_mir_borrowck(
 // if the MoveData is empty. Thankfully we can reset and ignore that error via
 // `Handler::reset_err_count` which we do by overriding optimized_mir.
 fn fake_optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> &'_ Body<'_> {
-  let mut providers = query::Providers::default();
+  let mut providers = Providers::default();
   rustc_mir_transform::provide(&mut providers);
   let body = (providers.optimized_mir)(tcx, did);
-  tcx.sess.diagnostic().reset_err_count();
+  tcx.sess.dcx().reset_err_count();
   body
 }
 
 // See `fake_mir_borrowck`
 pub fn override_queries(
   _session: &Session,
-  providers: &mut query::Providers,
-  _extern_providers: &mut query::ExternProviders,
+  providers: &mut rustc_middle::util::Providers,
 ) {
   providers.mir_borrowck = fake_mir_borrowck;
   providers.optimized_mir = fake_optimized_mir;
@@ -126,14 +125,12 @@ impl rustc_driver::Callbacks for InterpretCallbacks {
     }
   }
 
-  fn after_expansion<'tcx>(
+  fn after_analysis(
     &mut self,
     _compiler: &rustc_interface::interface::Compiler,
-    queries: &'tcx rustc_interface::Queries<'tcx>,
+    tcx: TyCtxt<'_>,
   ) -> rustc_driver::Compilation {
-    queries.global_ctxt().unwrap().enter(|tcx| {
-      self.result = Some(interpret(tcx));
-    });
+    self.result = Some(interpret(tcx));
     rustc_driver::Compilation::Stop
   }
 }
diff --git a/crates/aquascope/src/interpreter/mvalue.rs b/crates/aquascope/src/interpreter/mvalue.rs
index 9139af949..b3dc45aac 100644
--- a/crates/aquascope/src/interpreter/mvalue.rs
+++ b/crates/aquascope/src/interpreter/mvalue.rs
@@ -1,14 +1,15 @@
 //! Interpreting memory as Rust data types
 
 use miri::{
-  AllocKind, AllocMap, Immediate, InterpError, InterpErrorInfo, InterpResult,
-  MPlaceTy, MemPlaceMeta, MemoryKind, OpTy, Projectable, UndefinedBehaviorInfo,
+  interp_ok, AllocKind, AllocMap, CheckInAllocMsg, Immediate, InterpErrorInfo,
+  InterpErrorKind, InterpResult, MPlaceTy, MemPlaceMeta, MemoryKind, OpTy,
+  Projectable, UndefinedBehaviorInfo,
 };
 use rustc_abi::FieldsShape;
 use rustc_apfloat::Float;
 use rustc_middle::ty::{
   layout::{LayoutOf, TyAndLayout},
-  AdtKind, Ty, TyKind,
+  AdtKind, Ty, TyKind, TypingEnv,
 };
 use rustc_target::abi::Size;
 use rustc_type_ir::FloatTy;
@@ -61,13 +62,13 @@ impl<T> Abbreviated<T> {
   ) -> InterpResult<'tcx, Self> {
     if n <= ABBREV_MAX {
       let elts = (0 .. n).map(mk).collect::<InterpResult<'_, Vec<_>>>()?;
-      Ok(Abbreviated::All(elts))
+      interp_ok(Abbreviated::All(elts))
     } else {
       let initial = (0 .. ABBREV_MAX - 1)
         .map(&mut mk)
         .collect::<InterpResult<'tcx, Vec<_>>>()?;
       let last = mk(n - 1)?;
-      Ok(Abbreviated::Only(initial, Box::new(last)))
+      interp_ok(Abbreviated::Only(initial, Box::new(last)))
     }
   }
 
@@ -82,6 +83,15 @@ impl<T> Abbreviated<T> {
   }
 }
 
+// This type mirrors MHeapAllocKind, except it's allowed to store
+// non-serializable stuff from the compiler.
+#[derive(Copy, Clone)]
+enum HeapAllocKind<'tcx> {
+  String { len: u64 },
+  Vec { len: u64, el_ty: TyAndLayout<'tcx> },
+  Box,
+}
+
 #[derive(Serialize, Deserialize, Debug, TS, PartialEq, Copy, Clone)]
 #[serde(tag = "type", content = "value")]
 #[ts(export)]
@@ -91,6 +101,16 @@ pub enum MHeapAllocKind {
   Box,
 }
 
+impl From<HeapAllocKind<'_>> for MHeapAllocKind {
+  fn from(value: HeapAllocKind<'_>) -> Self {
+    match value {
+      HeapAllocKind::String { len } => MHeapAllocKind::String { len },
+      HeapAllocKind::Vec { len, .. } => MHeapAllocKind::Vec { len },
+      HeapAllocKind::Box => MHeapAllocKind::Box,
+    }
+  }
+}
+
 #[derive(Serialize, Deserialize, Debug, TS, PartialEq)]
 #[serde(tag = "type", content = "value")]
 #[ts(export)]
@@ -121,17 +141,17 @@ pub enum MValue {
   },
 }
 
-struct Reader<'a, 'mir, 'tcx> {
-  ev: &'a VisEvaluator<'mir, 'tcx>,
-  heap_alloc_kinds: Vec<MHeapAllocKind>,
+struct Reader<'a, 'tcx> {
+  ev: &'a VisEvaluator<'tcx>,
+  heap_alloc_kinds: Vec<HeapAllocKind<'tcx>>,
 }
 
-impl<'tcx> Reader<'_, '_, 'tcx> {
+impl<'tcx> Reader<'_, 'tcx> {
   fn get_path_segments(
     &mut self,
     alloc_size: Size,
     alloc_layout: TyAndLayout<'tcx>,
-    mplace: MPlaceTy<'tcx, miri::Provenance>,
+    mplace: MPlaceTy<'tcx>,
     target: Size,
   ) -> Vec<MPathSegment> {
     let segments = locate_address_in_type(
@@ -149,12 +169,12 @@ impl<'tcx> Reader<'_, '_, 'tcx> {
 
   fn read_alloc(
     &mut self,
-    base: miri::MPlaceTy<'tcx, miri::Provenance>,
+    base: miri::MPlaceTy<'tcx>,
   ) -> InterpResult<'tcx, MValue> {
     let el_ty = base.layout.ty;
     let stride = base.layout.size;
-    Ok(match self.heap_alloc_kinds.last() {
-      Some(MHeapAllocKind::String { len }) => {
+    interp_ok(match self.heap_alloc_kinds.last() {
+      Some(HeapAllocKind::String { len }) => {
         let array = self.read_array(base, stride, *len, el_ty)?;
         let MValue::Array(values) = array else {
           unreachable!()
@@ -165,23 +185,27 @@ impl<'tcx> Reader<'_, '_, 'tcx> {
         });
         MValue::Array(chars)
       }
-      Some(MHeapAllocKind::Vec { len }) => {
-        self.read_array(base, stride, *len, el_ty)?
+      Some(HeapAllocKind::Vec { len, el_ty }) => {
+        let stride = el_ty.layout.size;
+        self.read_array(base, stride, *len, el_ty.ty)?
       }
-      Some(MHeapAllocKind::Box) | None => self.read(&OpTy::from(base))?,
+      Some(HeapAllocKind::Box) | None => self.read(&OpTy::from(base))?,
     })
   }
 
   /// Reads a pointer, registering the pointed data for later use.
   fn read_pointer(
     &mut self,
-    mplace: miri::MPlaceTy<'tcx, miri::Provenance>,
+    mplace: miri::MPlaceTy<'tcx>,
   ) -> InterpResult<'tcx, MValue> {
     // Determine the base allocation from the mplace's provenance
-    let (alloc_id, offset, _) = self.ev.ecx.ptr_get_alloc_id(mplace.ptr)?;
-    let (alloc_size, _, alloc_status) = self.ev.ecx.get_alloc_info(alloc_id);
+    let (alloc_id, offset, _) = self
+      .ev
+      .ecx
+      .ptr_get_alloc_id(mplace.ptr(), mplace.layout().size.bytes() as i64)?;
+    let alloc_info = self.ev.ecx.get_alloc_info(alloc_id);
 
-    if matches!(alloc_status, AllocKind::Dead) {
+    if matches!(alloc_info.kind, AllocKind::Dead) {
       log::warn!("Reading a dead allocation");
     }
 
@@ -215,7 +239,7 @@ impl<'tcx> Reader<'_, '_, 'tcx> {
               Some(t) => t.clone(),
               None => {
                 drop(memory_map);
-                return Ok(MValue::Unallocated {
+                return interp_ok(MValue::Unallocated {
                   alloc_id: Some(self.ev.remap_alloc_id(alloc_id)),
                 });
               }
@@ -230,7 +254,13 @@ impl<'tcx> Reader<'_, '_, 'tcx> {
           // that property always holds.
           let index = memory_map.heap.locations.len();
           memory_map.heap.locations.push(mvalue);
-          (MMemorySegment::Heap { index }, mplace.layout)
+
+          let layout = match self.heap_alloc_kinds.last() {
+            Some(HeapAllocKind::Vec { el_ty, .. }) => *el_ty,
+            _ => mplace.layout,
+          };
+
+          (MMemorySegment::Heap { index }, layout)
         }
         _ => unimplemented!(),
       };
@@ -243,9 +273,9 @@ impl<'tcx> Reader<'_, '_, 'tcx> {
 
     // The pointer could point anywhere inside the allocation, so we use
     // `get_path_segments` to reverse-engineer a path from the memory location.
-    let meta = mplace.meta;
+    let meta = mplace.meta();
     let parts =
-      self.get_path_segments(alloc_size, alloc_layout, mplace, offset);
+      self.get_path_segments(alloc_info.size, alloc_layout, mplace, offset);
     let path = MPath { segment, parts };
 
     let range = match meta {
@@ -253,12 +283,12 @@ impl<'tcx> Reader<'_, '_, 'tcx> {
       MemPlaceMeta::None => None,
     };
 
-    Ok(MValue::Pointer { path, range })
+    interp_ok(MValue::Pointer { path, range })
   }
 
   fn read_array(
     &mut self,
-    base: MPlaceTy<'tcx, miri::Provenance>,
+    base: MPlaceTy<'tcx>,
     stride: Size,
     len: u64,
     el_ty: Ty<'tcx>,
@@ -270,32 +300,31 @@ impl<'tcx> Reader<'_, '_, 'tcx> {
       self.read(&offset_place.into())
     };
     let values = Abbreviated::new(len, read)?;
-    Ok(MValue::Array(values))
+    interp_ok(MValue::Array(values))
   }
 
   fn read_vec_len(
     &mut self,
-    op: &OpTy<'tcx, miri::Provenance>,
+    op: &OpTy<'tcx>,
   ) -> InterpResult<'tcx, Option<u64>> {
     let (_, len) = op.field_by_name("len", &self.ev.ecx)?;
-    let len = match self.read(&len) {
-      Ok(MValue::Unallocated { .. }) => return Ok(None),
-      Ok(MValue::Uint(len)) => len,
+    let len = match self.read(&len).unwrap() {
+      MValue::Unallocated { .. } => return interp_ok(None),
+      MValue::Uint(len) => len,
       _ => unreachable!(),
     };
-    Ok(Some(len))
+    interp_ok(Some(len))
   }
 
-  fn read(
-    &mut self,
-    op: &OpTy<'tcx, miri::Provenance>,
-  ) -> InterpResult<'tcx, MValue> {
+  fn read(&mut self, op: &OpTy<'tcx>) -> InterpResult<'tcx, MValue> {
+    let ecx = &self.ev.ecx;
+    let tcx = ecx.tcx;
     let ty = op.layout.ty;
 
     let result = match ty.kind() {
       _ if ty.is_box() => {
-        self.heap_alloc_kinds.push(MHeapAllocKind::Box);
-        let unique = self.ev.ecx.project_field(op, 0)?;
+        self.heap_alloc_kinds.push(HeapAllocKind::Box);
+        let unique = ecx.project_field(op, 0)?;
         let result = self.read(&unique)?;
         self.heap_alloc_kinds.pop();
         MValue::Adt {
@@ -309,7 +338,7 @@ impl<'tcx> Reader<'_, '_, 'tcx> {
       TyKind::Tuple(tys) => {
         let fields = (0 .. tys.len())
           .map(|i| {
-            let field_op = self.ev.ecx.project_field(op, i)?;
+            let field_op = ecx.project_field(op, i)?;
             self.read(&field_op)
           })
           .collect::<InterpResult<'tcx, Vec<_>>>()?;
@@ -317,15 +346,15 @@ impl<'tcx> Reader<'_, '_, 'tcx> {
         MValue::Tuple(fields)
       }
 
-      TyKind::Adt(adt_def, _) => {
+      TyKind::Adt(adt_def, args) => {
         let def_id = adt_def.did();
-        let name = self.ev.ecx.tcx.item_name(def_id).to_ident_string();
+        let name = tcx.item_name(def_id).to_ident_string();
 
         macro_rules! process_fields {
           ($op:expr, $fields:expr) => {{
             let mut fields = Vec::new();
             for (i, field) in $fields.enumerate() {
-              let field_op = self.ev.ecx.project_field($op, i)?;
+              let field_op = ecx.project_field($op, i)?;
 
               // Skip ZST fields since they don't exist at runtime
               if field_op.layout.is_zst() {
@@ -344,18 +373,24 @@ impl<'tcx> Reader<'_, '_, 'tcx> {
             let mut alloc_kind = None;
             match name.as_str() {
               "String" => {
-                let (_, vec) = op.field_by_name("vec", &self.ev.ecx)?;
+                let (_, vec) = op.field_by_name("vec", ecx)?;
                 if let Some(len) = self.read_vec_len(&vec)? {
-                  alloc_kind = Some(MHeapAllocKind::String { len });
+                  alloc_kind = Some(HeapAllocKind::String { len });
                 }
               }
               "Vec" => {
                 if let Some(len) = self.read_vec_len(op)? {
                   if !matches!(
                     self.heap_alloc_kinds.last(),
-                    Some(MHeapAllocKind::String { .. })
+                    Some(HeapAllocKind::String { .. })
                   ) {
-                    alloc_kind = Some(MHeapAllocKind::Vec { len });
+                    let el_ty = args[0].expect_ty();
+                    let el_ty = tcx
+                      .layout_of(
+                        TypingEnv::fully_monomorphized().as_query_input(el_ty),
+                      )
+                      .unwrap();
+                    alloc_kind = Some(HeapAllocKind::Vec { len, el_ty });
                   }
                 }
               }
@@ -376,12 +411,12 @@ impl<'tcx> Reader<'_, '_, 'tcx> {
               name,
               variant: None,
               fields,
-              alloc_kind,
+              alloc_kind: alloc_kind.map(Into::into),
             }
           }
           AdtKind::Enum => {
-            let variant_idx = self.ev.ecx.read_discriminant(op)?;
-            let casted = self.ev.ecx.project_downcast(op, variant_idx)?;
+            let variant_idx = ecx.read_discriminant(op)?;
+            let casted = ecx.project_downcast(op, variant_idx)?;
             let variant_def = adt_def.variant(variant_idx);
             let variant = variant_def.name.to_ident_string();
 
@@ -399,7 +434,7 @@ impl<'tcx> Reader<'_, '_, 'tcx> {
       }
 
       _ if ty.is_primitive() => {
-        let imm = match self.ev.ecx.read_immediate(op) {
+        let imm = match ecx.read_immediate(op).report_err() {
           Ok(imm) => imm,
 
           // It's possible to read uninitialized data if a data structure
@@ -407,10 +442,10 @@ impl<'tcx> Reader<'_, '_, 'tcx> {
           // is initialized. Therefore we have to handle this case by returning
           // MValue::Unallocated instead of throwing an error.
           Err(e) => match e.into_kind() {
-            InterpError::UndefinedBehavior(
+            InterpErrorKind::UndefinedBehavior(
               UndefinedBehaviorInfo::InvalidUninitBytes(..),
-            ) => return Ok(MValue::Unallocated { alloc_id: None }),
-            e => return Err(InterpErrorInfo::from(e)),
+            ) => return interp_ok(MValue::Unallocated { alloc_id: None }),
+            e => return Err(InterpErrorInfo::from(e)).into(),
           },
         };
         let Immediate::Scalar(scalar) = &*imm else {
@@ -421,17 +456,18 @@ impl<'tcx> Reader<'_, '_, 'tcx> {
           TyKind::Char => MValue::Char(scalar.to_char()? as usize),
           TyKind::Uint(uty) => MValue::Uint(match uty.bit_width() {
             Some(width) => scalar.to_uint(Size::from_bits(width))? as u64,
-            None => scalar.to_target_usize(&self.ev.ecx)?,
+            None => scalar.to_target_usize(ecx)?,
           }),
           TyKind::Int(ity) => MValue::Int(match ity.bit_width() {
             Some(width) => scalar.to_int(Size::from_bits(width))? as i64,
-            None => scalar.to_target_isize(&self.ev.ecx)?,
+            None => scalar.to_target_isize(ecx)?,
           }),
           TyKind::Float(fty) => MValue::Float(match fty {
             FloatTy::F32 => {
               f32::from_bits(scalar.to_f32()?.to_bits() as u32) as f64
             }
             FloatTy::F64 => f64::from_bits(scalar.to_f64()?.to_bits() as u64),
+            FloatTy::F16 | FloatTy::F128 => unimplemented!(),
           }),
           _ => unreachable!(),
         }
@@ -452,14 +488,26 @@ impl<'tcx> Reader<'_, '_, 'tcx> {
       }
 
       _ if ty.is_any_ptr() => {
-        let val = self.ev.ecx.read_immediate(op)?;
-        let mplace = self.ev.ecx.ref_to_mplace(&val)?;
-        if self.ev.ecx.check_mplace(&mplace).is_err() {
-          let alloc_id = match self.ev.ecx.ptr_get_alloc_id(mplace.ptr) {
+        let val = ecx.read_immediate(op)?;
+        let mplace = ecx.ref_to_mplace(&val)?;
+        if let Some((size, _)) = ecx.size_and_align_of_mplace(&mplace)?
+          && ecx
+            .check_ptr_access(
+              mplace.ptr(),
+              size,
+              CheckInAllocMsg::MemoryAccessTest,
+            )
+            .report_err()
+            .is_err()
+        {
+          let alloc_id = match ecx
+            .ptr_get_alloc_id(mplace.ptr(), mplace.layout().size.bytes() as i64)
+            .report_err()
+          {
             Ok((alloc_id, _, _)) => Some(self.ev.remap_alloc_id(alloc_id)),
             Err(_) => None,
           };
-          return Ok(MValue::Unallocated { alloc_id });
+          return interp_ok(MValue::Unallocated { alloc_id });
         }
         self.read_pointer(mplace)?
       }
@@ -470,7 +518,6 @@ impl<'tcx> Reader<'_, '_, 'tcx> {
 
         let upvar_names = match def_id.as_local() {
           Some(def_id) => {
-            let tcx = self.ev.ecx.tcx;
             let captures = tcx.closure_captures(def_id);
             captures
               .iter()
@@ -496,18 +543,15 @@ impl<'tcx> Reader<'_, '_, 'tcx> {
         }
       }
 
-      kind => todo!("{:?} / {:?}", **op, kind),
+      kind => todo!("{:?} / {:?}", op, kind),
     };
 
-    Ok(result)
+    interp_ok(result)
   }
 }
 
-impl<'tcx> VisEvaluator<'_, 'tcx> {
-  pub(super) fn read(
-    &self,
-    op: &OpTy<'tcx, miri::Provenance>,
-  ) -> InterpResult<'tcx, MValue> {
+impl<'tcx> VisEvaluator<'tcx> {
+  pub(super) fn read(&self, op: &OpTy<'tcx>) -> InterpResult<'tcx, MValue> {
     Reader {
       ev: self,
       heap_alloc_kinds: Vec::new(),
diff --git a/crates/aquascope/src/interpreter/step.rs b/crates/aquascope/src/interpreter/step.rs
index ac3d45a49..5ca275845 100644
--- a/crates/aquascope/src/interpreter/step.rs
+++ b/crates/aquascope/src/interpreter/step.rs
@@ -10,9 +10,9 @@ use anyhow::{anyhow, bail, Context, Result};
 use either::Either;
 use itertools::Itertools;
 use miri::{
-  AllocId, AllocMap, AllocRange, Immediate, InterpCx, InterpError,
-  InterpErrorInfo, InterpResult, LocalState, LocalValue, Machine, MiriConfig,
-  MiriMachine, OpTy, Operand, UndefinedBehaviorInfo,
+  interp_ok, AllocId, AllocMap, AllocRange, Immediate, InterpCx,
+  InterpErrorInfo, InterpErrorKind, InterpResult, LocalState, Machine,
+  MiriConfig, MiriMachine, OpTy, UndefinedBehaviorInfo,
 };
 use rustc_abi::{FieldsShape, Size};
 use rustc_const_eval::ReportErrorExt;
@@ -24,7 +24,7 @@ use rustc_middle::{
   },
   ty::{
     layout::{HasTyCtxt, TyAndLayout},
-    InstanceDef, TyCtxt,
+    Instance, TyCtxt,
   },
 };
 use rustc_session::CtfeBacktrace;
@@ -94,7 +94,7 @@ pub struct MTrace<L> {
   pub result: MResult,
 }
 
-pub(crate) type MirLoc<'tcx> = (InstanceDef<'tcx>, Either<Location, Span>);
+pub(crate) type MirLoc<'tcx> = (Instance<'tcx>, Either<Location, Span>);
 
 #[derive(Default)]
 pub(crate) struct MemoryMap<'tcx> {
@@ -120,7 +120,13 @@ impl<'tcx> MovedPlaces<'tcx> {
   }
 
   pub fn add_place(&mut self, frame: usize, place: Place<'tcx>) {
-    self.0.get_mut(frame).unwrap().insert(place);
+    self
+      .0
+      .get_mut(frame)
+      .unwrap_or_else(|| {
+        panic!("Tried to insert place at missing frame: {frame}")
+      })
+      .insert(place);
   }
 
   pub fn push_frame(&mut self) {
@@ -132,8 +138,8 @@ impl<'tcx> MovedPlaces<'tcx> {
   }
 }
 
-pub struct VisEvaluator<'mir, 'tcx> {
-  pub(super) ecx: InterpCx<'mir, 'tcx, MiriMachine<'mir, 'tcx>>,
+pub struct VisEvaluator<'tcx> {
+  pub(super) ecx: InterpCx<'tcx, MiriMachine<'tcx>>,
   pub(super) memory_map: RefCell<MemoryMap<'tcx>>,
   pub(super) moved_places: RefCell<MovedPlaces<'tcx>>,
 }
@@ -146,26 +152,26 @@ enum BodySpanType {
 /// Returns the span of a body, either just the header or the entire item
 fn body_span(tcx: TyCtxt, def_id: DefId, body_span_type: BodySpanType) -> Span {
   let hir = tcx.hir();
-  let fn_node = hir.body_owner(hir.body_owned_by(def_id.expect_local()));
+  let fn_node = hir.body_owner(hir.body_owned_by(def_id.expect_local()).id());
   match body_span_type {
     BodySpanType::Header => hir.span(fn_node),
     BodySpanType::Whole => hir.span_with_body(fn_node),
   }
 }
 
-type FrameLocals<'tcx> = Vec<(Local, String, OpTy<'tcx, miri::Provenance>)>;
-type MiriFrame<'mir, 'tcx> =
-  miri::Frame<'mir, 'tcx, miri::Provenance, miri::FrameExtra<'tcx>>;
+type FrameLocals<'tcx> = Vec<(Local, String, OpTy<'tcx>)>;
+type MiriFrame<'tcx> =
+  miri::Frame<'tcx, miri::Provenance, miri::FrameExtra<'tcx>>;
 
 #[derive(Copy, Clone)]
-struct LocalFrame<'a, 'mir, 'tcx> {
+struct LocalFrame<'a, 'tcx> {
   current: bool,
   local_index: usize,
   global_index: usize,
-  frame: &'a MiriFrame<'mir, 'tcx>,
+  frame: &'a MiriFrame<'tcx>,
 }
 
-impl<'mir, 'tcx> VisEvaluator<'mir, 'tcx> {
+impl<'tcx> VisEvaluator<'tcx> {
   pub fn new(tcx: TyCtxt<'tcx>) -> Result<Self> {
     let (main_id, entry_fn_type) = tcx
       .entry_fn(())
@@ -173,10 +179,11 @@ impl<'mir, 'tcx> VisEvaluator<'mir, 'tcx> {
     let ecx = miri::create_ecx(tcx, main_id, entry_fn_type, &MiriConfig {
       mute_stdout_stderr: true,
       // have to make sure miri doesn't complain about us poking around memory
-      validate: false,
+      validation: miri::ValidationMode::No,
       borrow_tracker: None,
       ..Default::default()
     })
+    .report_err()
     .map_err(|e| {
       anyhow!("{}", e.into_kind().diagnostic_message().as_str().unwrap())
     })?;
@@ -222,18 +229,18 @@ impl<'mir, 'tcx> VisEvaluator<'mir, 'tcx> {
       local_index,
       global_index,
       current,
-    }: LocalFrame<'_, 'mir, 'tcx>,
+    }: LocalFrame<'_, 'tcx>,
     loc_override: MirLoc<'tcx>,
     locals: FrameLocals<'tcx>,
   ) -> InterpResult<'tcx, MFrame<MirLoc<'tcx>>> {
     log::trace!("Building frame {local_index}");
 
-    let def_id = frame.instance.def_id();
+    let def_id = frame.instance().def_id();
     let name = self.fn_name(def_id);
 
     let tcx = *self.ecx.tcx;
     let body_span = CharRange::from_span(
-      body_span(tcx, frame.instance.def_id(), BodySpanType::Whole),
+      body_span(tcx, frame.instance().def_id(), BodySpanType::Whole),
       tcx.sess.source_map(),
     )
     .unwrap();
@@ -241,7 +248,7 @@ impl<'mir, 'tcx> VisEvaluator<'mir, 'tcx> {
     let current_loc = if current {
       loc_override
     } else {
-      (frame.instance.def, frame.current_loc())
+      (frame.instance(), frame.current_loc())
     };
 
     let moved_places = self.moved_places.borrow();
@@ -268,7 +275,7 @@ impl<'mir, 'tcx> VisEvaluator<'mir, 'tcx> {
             .collect::<Vec<_>>(),
           None => Vec::new(),
         };
-        Ok(MLocal {
+        interp_ok(MLocal {
           name,
           value,
           moved_paths,
@@ -276,7 +283,7 @@ impl<'mir, 'tcx> VisEvaluator<'mir, 'tcx> {
       })
       .collect::<InterpResult<'_, Vec<_>>>()?;
 
-    Ok(MFrame {
+    interp_ok(MFrame {
       name,
       body_span,
       locals,
@@ -287,7 +294,11 @@ impl<'mir, 'tcx> VisEvaluator<'mir, 'tcx> {
   pub(super) fn mem_is_initialized(
     &self,
     layout: TyAndLayout<'tcx>,
-    allocation: &miri::Allocation<miri::Provenance, miri::AllocExtra>,
+    allocation: &miri::Allocation<
+      miri::Provenance,
+      miri::AllocExtra,
+      miri::MiriAllocBytes,
+    >,
   ) -> bool {
     // TODO: this should be recursive over the type. Only handles one-step right now.
     let ranges = match &layout.fields {
@@ -317,17 +328,17 @@ impl<'mir, 'tcx> VisEvaluator<'mir, 'tcx> {
 
   fn test_local(
     &self,
-    frame: &MiriFrame<'mir, 'tcx>,
+    frame: &MiriFrame<'tcx>,
     frame_index: usize,
     local: Local,
     state: &LocalState<'tcx, miri::Provenance>,
-  ) -> InterpResult<'tcx, Option<(String, OpTy<'tcx, miri::Provenance>)>> {
-    let decl = &frame.body.local_decls[local];
+  ) -> InterpResult<'tcx, Option<(String, OpTy<'tcx>)>> {
+    let decl = &frame.body().local_decls[local];
     let name = if local == RETURN_PLACE {
       // Don't include unit return types in locals
       if decl.ty.is_unit() {
         log::trace!("Ignoring local {local:?} because it's a unit type");
-        return Ok(None);
+        return interp_ok(None);
       }
 
       "(return)".into()
@@ -336,7 +347,7 @@ impl<'mir, 'tcx> VisEvaluator<'mir, 'tcx> {
       // visualize in the case of f(&Some(x)). Need to figure out a good strategy for
       // deciding when a temp should be included.
       let has_debug_info = frame
-        .body
+        .body()
         .var_debug_info
         .iter()
         .filter_map(|info| match info.value {
@@ -354,60 +365,59 @@ impl<'mir, 'tcx> VisEvaluator<'mir, 'tcx> {
         log::trace!(
           "Ignoring local {local:?} because it's not a source-level variable"
         );
-        return Ok(None);
+        return interp_ok(None);
       }
 
       Place::from_local(local, *self.ecx.tcx)
-        .to_string(*self.ecx.tcx, frame.body)
+        .to_string(*self.ecx.tcx, frame.body())
         .unwrap_or_else(|| String::from("(tmp)"))
     };
 
-    let layout = state.layout.get();
-
     // Ignore dead locals
-    let LocalValue::Live(op) = state.value else {
+    let Some(op) = state.as_mplace_or_imm() else {
       log::trace!("Ignoring local {local:?} because it's not live");
-      return Ok(None);
+      return interp_ok(None);
     };
 
+    let layout = self.ecx.layout_of_local(frame, local, None)?;
+
     match op {
       // Ignore uninitialized locals
-      Operand::Immediate(Immediate::Uninit) => {
+      Either::Right(Immediate::Uninit) => {
         // Special case: a unit struct is considered uninitialized, but we would still like to
         // visualize it at the toplevel, so we handle that here. Might need to make this a configurable thing?
-        let not_zst = match layout {
-          Some(layout) => !layout.is_zst(),
-          None => true,
-        };
-        if not_zst {
+        if !layout.is_zst() {
           log::trace!("Ignoring local {local:?} because it's uninitialized and not zero-sized");
-          return Ok(None);
+          return interp_ok(None);
         }
       }
 
       // If a local is Indirect, meaning there exists a pointer to it,
       // then save its allocation in `MemoryMap::stack_slots`
-      Operand::Indirect(mplace) => {
+      Either::Left((ptr, _)) => {
         let mut memory_map = self.memory_map.borrow_mut();
-        let (alloc_id, _, _) = self.ecx.ptr_get_alloc_id(mplace.ptr).unwrap();
+        let (alloc_id, _, _) = self
+          .ecx
+          .ptr_get_alloc_id(ptr, layout.size.bytes() as i64)
+          .unwrap();
 
         // Have to handle the case that a local is uninitialized and indirect
         let (_, allocation) =
           self.ecx.memory.alloc_map().get(alloc_id).unwrap();
-        if !self.mem_is_initialized(layout.unwrap(), allocation) {
+        if !self.mem_is_initialized(layout, allocation) {
           log::trace!("Ignoring local {local:?} because it's a pointer to uninitialized memory");
-          return Ok(None);
+          return interp_ok(None);
         }
 
         memory_map
           .stack_slots
-          .insert(alloc_id, (frame_index, name.clone(), layout.unwrap()));
+          .insert(alloc_id, (frame_index, name.clone(), layout));
       }
       _ => {}
     };
 
-    let op_ty = self.ecx.local_to_op(frame, local, layout)?;
-    Ok(Some((name, op_ty)))
+    let op_ty = self.ecx.local_at_frame_to_op(frame, local, Some(layout))?;
+    interp_ok(Some((name, op_ty)))
   }
 
   fn find_locals(&self) -> InterpResult<'tcx, Vec<FrameLocals<'tcx>>> {
@@ -423,8 +433,9 @@ impl<'mir, 'tcx> VisEvaluator<'mir, 'tcx> {
             .filter_map(|(local, state)| {
               let local_data_res = self
                 .test_local(frame, local_index, local, state)
+                .report_err()
                 .transpose()?;
-              Some(local_data_res.map(|(name, op)| (local, name, op)))
+              Some(local_data_res.map(|(name, op)| (local, name, op)).into())
             })
             .collect::<InterpResult<'tcx, Vec<_>>>()
         },
@@ -442,7 +453,7 @@ impl<'mir, 'tcx> VisEvaluator<'mir, 'tcx> {
       .zip(locals)
       .map(|(frame, locals)| self.build_frame(frame, current_loc, locals))
       .collect::<InterpResult<'_, _>>()?;
-    Ok(MStack { frames })
+    interp_ok(MStack { frames })
   }
 
   fn build_heap(&self) -> MHeap {
@@ -458,24 +469,24 @@ impl<'mir, 'tcx> VisEvaluator<'mir, 'tcx> {
     log::trace!("Building stack");
     let stack = self.build_stack(current_loc)?;
     if stack.frames.is_empty() {
-      return Ok(None);
+      return interp_ok(None);
     }
 
     log::trace!("Building heap");
     let heap = self.build_heap();
 
     log::trace!("Step built!");
-    Ok(Some(MStep { stack, heap }))
+    interp_ok(Some(MStep { stack, heap }))
   }
 
   /// Get the stack frames for functions defined in the local crate
-  fn local_frames(&self) -> impl Iterator<Item = LocalFrame<'_, 'mir, 'tcx>> {
+  fn local_frames(&self) -> impl Iterator<Item = LocalFrame<'_, 'tcx>> {
     let stack = Machine::stack(&self.ecx);
     let n = stack.len();
     stack
       .iter()
       .enumerate()
-      .filter(|(_, frame)| frame.instance.def_id().is_local())
+      .filter(|(_, frame)| frame.instance().def_id().is_local())
       .enumerate()
       .map(move |(local_index, (global_index, frame))| LocalFrame {
         current: global_index == n - 1,
@@ -488,10 +499,10 @@ impl<'mir, 'tcx> VisEvaluator<'mir, 'tcx> {
   fn collect_moves(&self) -> InterpResult<'tcx, Vec<Place<'tcx>>> {
     let stack = Machine::stack(&self.ecx);
     let Some(frame) = stack.last() else {
-      return Ok(Vec::new());
+      return interp_ok(Vec::new());
     };
     let Either::Left(loc) = frame.current_loc() else {
-      return Ok(Vec::new());
+      return interp_ok(Vec::new());
     };
 
     struct CollectMoves<'tcx> {
@@ -511,9 +522,9 @@ impl<'mir, 'tcx> VisEvaluator<'mir, 'tcx> {
     }
 
     let mut collector = CollectMoves { places: Vec::new() };
-    collector.visit_location(frame.body, loc);
+    collector.visit_location(frame.body(), loc);
 
-    Ok(collector.places)
+    interp_ok(collector.places)
   }
 
   fn handle_moves(
@@ -533,28 +544,29 @@ impl<'mir, 'tcx> VisEvaluator<'mir, 'tcx> {
             Either::Left(_mplace) => {
               // todo!()
             }
-            Either::Right((frame, local, _)) => {
-              moved_places
-                .add_place(frame, Place::from_local(local, self.ecx.tcx()));
+            Either::Right((local, ..)) => {
+              moved_places.add_place(
+                n_frames - 1,
+                Place::from_local(local, self.ecx.tcx()),
+              );
             }
           }
         }
       }
     }
 
-    Ok(())
+    interp_ok(())
   }
 
   /// Take a single (local) step, internally stepping until we reach a serialization point
   fn step(
     &mut self,
   ) -> InterpResult<'tcx, (Option<MStep<MirLoc<'tcx>>>, bool)> {
-    let get_current_local_loc =
-      |local_frames: &[LocalFrame<'_, 'mir, 'tcx>]| {
-        let LocalFrame { frame, .. } = local_frames.last()?;
-        let loc = frame.current_loc();
-        Some((frame.instance.def, loc))
-      };
+    let get_current_local_loc = |local_frames: &[LocalFrame<'_, 'tcx>]| {
+      let LocalFrame { frame, .. } = local_frames.last()?;
+      let loc = frame.current_loc();
+      Some((frame.instance(), loc))
+    };
 
     loop {
       let local_frames = self.local_frames().collect::<Vec<_>>();
@@ -578,16 +590,16 @@ impl<'mir, 'tcx> VisEvaluator<'mir, 'tcx> {
           let LocalFrame { frame, .. } = local_frames_after.last().unwrap();
           let span = body_span(
             *self.ecx.tcx,
-            frame.instance.def_id(),
+            frame.instance().def_id(),
             BodySpanType::Header,
           );
 
-          Some((frame.instance.def, Either::Right(span)))
+          Some((frame.instance(), Either::Right(span)))
         }
         Ordering::Less => {
           if let Some(caller_frame_loc) = caller_frame_loc {
             let LocalFrame { frame, .. } = local_frames_after.last().unwrap();
-            Some((frame.instance.def, caller_frame_loc))
+            Some((frame.instance(), caller_frame_loc))
           } else {
             current_loc_opt
           }
@@ -597,12 +609,12 @@ impl<'mir, 'tcx> VisEvaluator<'mir, 'tcx> {
 
       if let Some(current_loc) = current_loc_opt {
         if let Some(step) = self.build_step(current_loc)? {
-          return Ok((Some(step), more_work));
+          return interp_ok((Some(step), more_work));
         }
       }
 
       if !more_work {
-        return Ok((None, more_work));
+        return interp_ok((None, more_work));
       }
     }
   }
@@ -614,7 +626,7 @@ impl<'mir, 'tcx> VisEvaluator<'mir, 'tcx> {
     use UndefinedBehaviorInfo::PointerUseAfterFree;
 
     Ok(match e.into_kind() {
-      InterpError::UndefinedBehavior(ub) => match ub {
+      InterpErrorKind::UndefinedBehavior(ub) => match ub {
         PointerUseAfterFree(alloc_id, _) => {
           MUndefinedBehavior::PointerUseAfterFree {
             alloc_id: self.remap_alloc_id(alloc_id),
@@ -632,7 +644,7 @@ impl<'mir, 'tcx> VisEvaluator<'mir, 'tcx> {
   pub fn eval(&mut self) -> Result<MTrace<MirLoc<'tcx>>> {
     let mut steps = Vec::new();
     let result = loop {
-      match self.step() {
+      match self.step().report_err() {
         Ok((step, more_work)) => {
           if let Some(step) = step {
             steps.push(step);
diff --git a/crates/aquascope_front/Cargo.toml b/crates/aquascope_front/Cargo.toml
index 2ff5328a8..b95566b03 100644
--- a/crates/aquascope_front/Cargo.toml
+++ b/crates/aquascope_front/Cargo.toml
@@ -23,9 +23,9 @@ serde_json = "1"
 ts-rs = "6.2"
 itertools = "0.10.5"
 fluid-let = "1.0"
-rustc_plugin = "0.7.0-nightly-2023-08-25"
-rustc_utils = "0.7.0-nightly-2023-08-25"
+rustc_plugin = { workspace = true }
+rustc_utils = { workspace = true }
 
 # For binaries
-env_logger = {version = "0.9", default-features = false}
+env_logger = {version = "0.9", default-features = false, features = ["humantime"]}
 clap = {version = "3.1", default-features = false, features = ["std", "derive"]}
diff --git a/crates/aquascope_front/src/bin/aquascope-driver.rs b/crates/aquascope_front/src/bin/aquascope-driver.rs
index 6578dcf3a..239bd286e 100644
--- a/crates/aquascope_front/src/bin/aquascope-driver.rs
+++ b/crates/aquascope_front/src/bin/aquascope-driver.rs
@@ -1,3 +1,5 @@
+#![feature(rustc_private)]
+
 use std::{ffi::OsStr, io::Write, path::Path};
 
 fn main() {
diff --git a/crates/aquascope_front/src/bin/cargo-aquascope.rs b/crates/aquascope_front/src/bin/cargo-aquascope.rs
index f7889b3bc..9389004af 100644
--- a/crates/aquascope_front/src/bin/cargo-aquascope.rs
+++ b/crates/aquascope_front/src/bin/cargo-aquascope.rs
@@ -1,3 +1,5 @@
+#![feature(rustc_private)]
+
 fn main() {
   env_logger::init();
   rustc_plugin::cli_main(aquascope_front::AquascopePlugin);
diff --git a/crates/aquascope_front/src/plugin.rs b/crates/aquascope_front/src/plugin.rs
index f3dd3ed7f..e62bb52a3 100644
--- a/crates/aquascope_front/src/plugin.rs
+++ b/crates/aquascope_front/src/plugin.rs
@@ -12,7 +12,9 @@ use aquascope::{
     stepper::{PermIncludeMode, INCLUDE_MODE},
     AquascopeError, AquascopeResult,
   },
-  errors::{initialize_error_tracking, track_body_diagnostics},
+  errors::{
+    initialize_error_tracking, silent::silent_session, track_body_diagnostics,
+  },
 };
 use clap::{Parser, Subcommand};
 use fluid_let::fluid_set;
@@ -174,9 +176,10 @@ pub fn run_with_callbacks(
 
   log::debug!("building compiler ...");
 
-  compiler
-    .run()
-    .map_err(|_| AquascopeError::BuildError { range: None })
+  rustc_driver::catch_fatal_errors(move || {
+    compiler.run();
+  })
+  .map_err(|_| AquascopeError::BuildError { range: None })
 }
 
 pub trait AquascopeAnalysis: Sized + Send + Sync {
@@ -217,13 +220,14 @@ struct AquascopeCallbacks<A: AquascopeAnalysis> {
 
 impl<A: AquascopeAnalysis> rustc_driver::Callbacks for AquascopeCallbacks<A> {
   fn config(&mut self, config: &mut rustc_interface::Config) {
+    config.psess_created = Some(silent_session());
     config.override_queries = Some(borrowck_facts::override_queries);
   }
 
-  fn after_expansion<'tcx>(
+  fn after_expansion(
     &mut self,
     _compiler: &rustc_interface::interface::Compiler,
-    queries: &'tcx rustc_interface::Queries<'tcx>,
+    tcx: TyCtxt<'_>,
   ) -> rustc_driver::Compilation {
     // Setting up error tracking happens here. Within rustc callbacks
     // seem to be set up *after* `config` is called.
@@ -234,14 +238,12 @@ impl<A: AquascopeAnalysis> rustc_driver::Callbacks for AquascopeCallbacks<A> {
 
     let _start = Instant::now();
 
-    queries.global_ctxt().unwrap().enter(|tcx| {
-      let mut analysis = self.analysis.take().unwrap();
-      find_bodies(tcx).into_iter().for_each(|(_, body_id)| {
-        // Track diagnostics for the analysis of the current body
-        let def_id = tcx.hir().body_owner_def_id(body_id);
-        track_body_diagnostics(def_id);
-        self.output.push(analysis.analyze(tcx, body_id));
-      });
+    let mut analysis = self.analysis.take().unwrap();
+    find_bodies(tcx).into_iter().for_each(|(_, body_id)| {
+      // Track diagnostics for the analysis of the current body
+      let def_id = tcx.hir().body_owner_def_id(body_id);
+      track_body_diagnostics(def_id);
+      self.output.push(analysis.analyze(tcx, body_id));
     });
 
     log::debug!("Callback analysis took {:?}", self.rustc_start.elapsed());
diff --git a/crates/aquascope_serve/Cargo.toml b/crates/aquascope_serve/Cargo.toml
index 585cea138..d23717c1a 100644
--- a/crates/aquascope_serve/Cargo.toml
+++ b/crates/aquascope_serve/Cargo.toml
@@ -11,25 +11,18 @@ default-run = "aquascope_serve"
 repository = "https://github.com/cognitive-engineering-lab/aquascope"
 publish = false
 
-[features]
-no-docker = ["tempfile"]
-
 [dependencies]
+anyhow = "1"
+aquascope_workspace_utils = {version = "0.3",  path = "../aquascope_workspace_utils"}
 async-trait = "0.1.52"
 axum = { version = "0.5" }
 env_logger = "0.9.0"
 futures = "0.3.21"
 log = "0.4.0"
-serde = { workspace = true }
+serde.workspace = true
 serde_json = "1.0"
 snafu = "0.7.0"
-tokio = { version = "1.9", features = ["macros", "time", "process"] }
+tokio = { version = "1.9", features = ["macros", "time", "process", "rt-multi-thread"] }
 tower-http = { version = "0.3", features = ["cors", "trace"] }
-bollard = "0.13"
 tar = "0.4"
-
-# No docker
-tempfile = { version = "3.3.0", optional = true }
-
-[dev-dependencies]
-lazy_static = "1"
+tempfile = "3.3.0"
diff --git a/crates/aquascope_serve/README.md b/crates/aquascope_serve/README.md
index d935a736b..1130b08eb 100644
--- a/crates/aquascope_serve/README.md
+++ b/crates/aquascope_serve/README.md
@@ -1,3 +1,7 @@
-Currently, most of the code in this crate is a modified version of both:
+# Aquascope Server
+
+> ❗ The Aquascope server is now _only_ used for debugging. The published playground uses a WASM build of the project to evaluate requests. This means that the server runs all requests on *your machine*, so don't do anything stupid ;)
+
+Much of the code in this crate is a modified version of both:
 - https://github.com/willcrichton/situ/tree/main/backend/crates/situ-server
 - https://github.com/integer32llc/rust-playground
diff --git a/crates/aquascope_serve/rustfmt.toml b/crates/aquascope_serve/rustfmt.toml
deleted file mode 100644
index 65bcc160f..000000000
--- a/crates/aquascope_serve/rustfmt.toml
+++ /dev/null
@@ -1,4 +0,0 @@
-newline_style = "unix"
-comment_width = 80
-edition = "2021"
-wrap_comments = true
diff --git a/crates/aquascope_serve/src/container.rs b/crates/aquascope_serve/src/container.rs
index 41688bbcf..56bb89fab 100644
--- a/crates/aquascope_serve/src/container.rs
+++ b/crates/aquascope_serve/src/container.rs
@@ -1,52 +1,37 @@
-use snafu::prelude::*;
+use std::{
+  fs, io, os::unix::fs::PermissionsExt, path::PathBuf, str, time::Duration,
+};
 
-use std::{io, os::unix::fs::PermissionsExt, path::PathBuf, str, time::Duration};
+use aquascope_workspace_utils::miri_sysroot;
+use snafu::prelude::*;
+use tempfile::{tempdir, TempDir};
 use tokio::{self, process::Command, time};
 
 use crate::{ServerResponse, SingleFileRequest};
 
-#[cfg(not(feature = "no-docker"))]
-use {
-    bollard::{
-        container::{
-            Config, CreateContainerOptions, LogOutput, RemoveContainerOptions,
-            StartContainerOptions, UploadToContainerOptions,
-        },
-        exec::{CreateExecOptions, StartExecResults},
-        models::{ContainerCreateResponse, HostConfig},
-        Docker,
-    },
-    futures::StreamExt,
-    serde::Serialize,
-    std::{env, iter, path::Path, sync::Arc},
-};
-
-#[cfg(feature = "no-docker")]
-use {
-    std::fs,
-    tempfile::{tempdir, TempDir},
-};
-
 #[derive(Debug, Snafu)]
 pub enum Error {
-    #[snafu(display("Bollard operation failed {}", source))]
-    Bollard { source: bollard::errors::Error },
-    #[snafu(display("Unable to create temporary local directory {}", source))]
-    UnableToCreateTempDir { source: io::Error },
-    #[snafu(display("Unable to create output directory: {}", source))]
-    UnableToWriteFile { source: io::Error },
-    #[snafu(display("Unable to execute local command {}", source))]
-    UnableToExecCommand { source: io::Error },
-    #[snafu(display("Unable to create source file: {}", source))]
-    UnableToCreateSourceFile { source: io::Error },
-    #[snafu(display("Unable to launch the docker container: {}", source))]
-    UnableToStartDocker { source: io::Error },
-
-    #[snafu(display("Command execution took longer than {} ms", timeout.as_millis()))]
-    CommandExecTimedOut {
-        source: time::error::Elapsed,
-        timeout: Duration,
-    },
+  #[snafu(display("Unable to create temporary local directory {}", source))]
+  UnableToCreateTempDir { source: io::Error },
+  #[snafu(display("Unable to create output directory: {}", source))]
+  UnableToWriteFile { source: io::Error },
+  #[snafu(display("Unable to execute local command {}", source))]
+  UnableToExecCommand { source: io::Error },
+  #[snafu(display("Unable to create source file: {}", source))]
+  UnableToCreateSourceFile { source: io::Error },
+  #[snafu(display("Command execution took longer than {} ms", timeout.as_millis()))]
+  CommandExecTimedOut {
+    source: time::error::Elapsed,
+    timeout: Duration,
+  },
+  #[snafu(display("Miscellaneous error: {}", source))]
+  Misc { source: anyhow::Error },
+}
+
+impl From<anyhow::Error> for Error {
+  fn from(e: anyhow::Error) -> Self {
+    Error::Misc { source: e }
+  }
 }
 
 pub type Result<T, E = Error> = ::std::result::Result<T, E>;
@@ -55,545 +40,220 @@ const DEFAULT_IMAGE: &str = "aquascope";
 const DEFAULT_PROJECT_PATH: &str = "aquascope_tmp_proj";
 
 const COMMAND_TIMEOUT: Duration = Duration::from_secs(20);
-// Memory limit in bytes.
-const DOCKER_MEM_LIMIT: i64 = 512_000_000;
-// Swap limit in bytes (when MEM_LIMIT == SWAP_LIMIT no swap is allowed).
-const DOCKER_SWAP_LIMIT: i64 = 512_000_000;
-const DOCKER_PID_LIMIT: i64 = 32;
-// Default docker `--cpu-quota` is 100000 microseconds
-// `--cpus` is a better flag to use but Bollard doesn't provide this.
-const DOCKER_CPU_PERIOD: i64 = 100_000;
-// Cap a container to use 50% of one available CPU.
-const DOCKER_CPU_QUOTA: i64 = DOCKER_CPU_PERIOD / 2;
-
-#[cfg(not(feature = "no-docker"))]
-pub struct Container {
-    id: String,
-    killed: bool,
-    project_dir: Option<String>,
-    docker: Arc<Docker>,
-}
 
-#[cfg(feature = "no-docker")]
 pub struct Container {
-    project_dir: Option<String>,
-    workspace: TempDir,
+  project_dir: Option<String>,
+  workspace: TempDir,
 }
 
 impl Container {
-    #[cfg(feature = "no-docker")]
-    pub async fn new() -> Result<Self> {
-        let td = tempdir().context(UnableToCreateTempDirSnafu)?;
-        let mut this = Container {
-            workspace: td,
-            project_dir: None,
-        };
-
-        this.cargo_new().await?;
-
-        Ok(this)
-    }
-
-    #[cfg(not(feature = "no-docker"))]
-    pub async fn new() -> Result<Self> {
-        let d = Docker::connect_with_local_defaults()?.with_timeout(COMMAND_TIMEOUT);
-        let docker = Arc::new(d);
-        docker.ping().await?;
-        let image = DEFAULT_IMAGE;
-
-        Self::with_docker(docker, image).await
-    }
-
-    #[cfg(not(feature = "no-docker"))]
-    pub(crate) async fn with_docker(docker: Arc<Docker>, image: &str) -> Result<Self> {
-        // Launch the container with
-        let options: Option<CreateContainerOptions<String>> = None;
-        let cwd = env::current_dir().unwrap();
-        let mount_path = cwd.join("mount");
-        let config = Config {
-            tty: Some(true), // to keep the container alive
-            image: Some(image),
-            host_config: Some(HostConfig {
-                cpu_period: Some(DOCKER_CPU_PERIOD),
-                cpu_quota: Some(DOCKER_CPU_QUOTA),
-                memory: Some(DOCKER_MEM_LIMIT),
-                memory_swap: Some(DOCKER_SWAP_LIMIT),
-                pids_limit: Some(DOCKER_PID_LIMIT),
-                binds: Some(vec![format!("{}:/mnt", mount_path.display())]),
-                ..Default::default()
-            }),
-            ..Default::default()
-        };
-        let ContainerCreateResponse { id, .. } = docker.create_container(options, config).await?;
-        log::info!("Created container with id: {id}");
-
-        let options: Option<StartContainerOptions<String>> = None;
-        docker.start_container(&id, options).await?;
-        log::info!("Container started: {id}");
-
-        let mut this = Container {
-            id,
-            killed: false,
-            docker: docker.clone(),
-            project_dir: None,
-        };
-
-        this.cargo_new().await?;
-
-        Ok(this)
-    }
-
-    #[cfg(not(feature = "no-docker"))]
-    pub async fn exec(
-        &self,
-        options: CreateExecOptions<impl Into<String> + Serialize>,
-    ) -> Result<StartExecResults, Error> {
-        let exec = self.docker.create_exec(&self.id, options).await?;
-        self.docker
-            .start_exec(&exec.id, None)
-            .await
-            .context(BollardSnafu)
-    }
-
-    #[allow(dead_code)]
-    pub async fn get_pid(&self, process: &str) -> Result<i64> {
-        let mut cmd = Command::new("pidof");
-        cmd.arg(process);
-        let (response, _) = self.exec_output(&mut cmd).await?;
-        Ok(response
-            .split(' ')
-            .next()
-            .unwrap()
-            .parse::<i64>()
-            .unwrap_or_else(|_| {
-                panic!(
-                    "Invalid response in get_pid:
+  pub async fn new() -> Result<Self> {
+    let td = tempdir().context(UnableToCreateTempDirSnafu)?;
+    let mut this = Container {
+      workspace: td,
+      project_dir: None,
+    };
+
+    this.cargo_new().await?;
+
+    Ok(this)
+  }
+
+  #[allow(dead_code)]
+  pub async fn get_pid(&self, process: &str) -> Result<i64> {
+    let mut cmd = Command::new("pidof");
+    cmd.arg(process);
+    let (response, _) = self.exec_output(&mut cmd).await?;
+    Ok(
+      response
+        .split(' ')
+        .next()
+        .unwrap()
+        .parse::<i64>()
+        .unwrap_or_else(|_| {
+          panic!(
+            "Invalid response in get_pid:
     {response}"
-                )
-            }))
-    }
-
-    #[cfg(feature = "no-docker")]
-    pub async fn exec_output(&self, cmd: &mut Command) -> Result<(String, String)> {
-        let timeout = COMMAND_TIMEOUT;
-        let cmd = cmd.current_dir(self.cwd());
-        let timed_out = match time::timeout(timeout, cmd.output()).await {
-            Ok(Ok(output)) => Ok(output),
-            // failure
-            Ok(e @ Err(_)) => return e.map(|_| unreachable!()).context(UnableToExecCommandSnafu),
-            // timeout
-            Err(e) => Err(e),
-        };
-
-        let output = timed_out.context(CommandExecTimedOutSnafu { timeout })?;
-
-        // TODO: FIXME
-        let stdout = String::from_utf8(output.stdout).unwrap();
-        let stderr = String::from_utf8(output.stderr).unwrap();
-
-        // use info here because the "no-docker" feature is used primarily
-        // as a debugging target.
-        log::info!("{}", stderr);
-
-        Ok((stdout, stderr))
-    }
-
-    // Returns (Stdout, Stderr)
-    #[cfg(not(feature = "no-docker"))]
-    #[allow(clippy::needless_pass_by_ref_mut)]
-    pub async fn exec_output(&self, cmd: &mut Command) -> Result<(String, String)> {
-        // Convert back to std::process::Command for access to get_XXX functions.
-        let cmd = cmd.as_std();
-        let args = iter::once(cmd.get_program())
-            .chain(cmd.get_args())
-            .map(|s| s.to_string_lossy().to_string())
-            .collect::<Vec<_>>();
-        let env = cmd
-            .get_envs()
-            .map(|(k, v)| {
-                let ks = k.to_string_lossy();
-                match v {
-                    Some(v) => format!("{ks}={}", v.to_string_lossy()),
-                    None => format!("{ks}="),
-                }
-            })
-            .collect::<Vec<_>>();
-        let working_dir = cmd
-            .get_current_dir()
-            .map(|p| p.to_string_lossy().to_string());
-        let exec = self
-            .exec(CreateExecOptions {
-                attach_stdout: Some(true),
-                attach_stderr: Some(true),
-                working_dir,
-                env: Some(env),
-                cmd: Some(args),
-                ..Default::default()
-            })
-            .await?;
-
-        macro_rules! get_variant_as_string {
-            ($id:path, $e:expr) => {
-                if let $id { message } = $e {
-                    String::from_utf8_lossy(message.as_ref()).to_string()
-                } else {
-                    unreachable!()
-                }
-            };
-        }
-
-        if let StartExecResults::Attached { output, .. } = exec {
-            let timeout = COMMAND_TIMEOUT;
-            let lines = time::timeout(
-                timeout,
-                output
-                    .filter_map(|log| async move {
-                        match log {
-                            Ok(LogOutput::StdOut { message }) => {
-                                Some(LogOutput::StdOut { message })
-                            }
-
-                            Ok(LogOutput::StdErr { message }) => {
-                                Some(LogOutput::StdErr { message })
-                            }
-                            _ => None,
-                        }
-                    })
-                    .collect::<Vec<_>>(),
-            )
-            .await
-            .context(CommandExecTimedOutSnafu { timeout })?;
-
-            let (stdout, stderr): (Vec<_>, Vec<_>) = lines
-                .iter()
-                .partition(|e| matches!(e, LogOutput::StdOut { .. }));
-
-            let stdout = stdout
-                .iter()
-                .map(|stdout| get_variant_as_string!(LogOutput::StdOut, stdout))
-                .collect::<Vec<_>>();
-
-            let stderr = stderr
-                .iter()
-                .map(|stderr| get_variant_as_string!(LogOutput::StdErr, stderr))
-                .collect::<Vec<_>>();
-
-            Ok((
-                stdout.join("\n").trim_end().to_owned(),
-                stderr.join("\n").trim_end().to_owned(),
-            ))
-        } else {
-            unreachable!()
-        }
-    }
-
-    // XXX: in theory this should probably be a default part of the
-    // container. It would be great if we could also allow people
-    // to have a full project open in the editor but I don't see this
-    // for the near future.
-    async fn cargo_new(&mut self) -> Result<()> {
-        if self.project_dir.is_some() {
-            log::warn!("Attempt to create a second project directory ignored");
-            return Ok(());
-        }
-
-        let pwd = DEFAULT_PROJECT_PATH;
-
-        let mut cmd = Command::new("cargo");
-        cmd.args(["new", "--bin", pwd, "--quiet"]);
-
-        let (output_s, stderr) = self.exec_output(&mut cmd).await?;
-
-        if !stderr.trim().is_empty() {
-            log::error!("{}", stderr);
-            panic!("`cargo new` failed {stderr}");
-        }
-
-        log::debug!("Cargo output {}", output_s);
-
-        self.project_dir = Some(pwd.to_owned());
-
-        Ok(()) // TODO what happens when we can't create the new directory?
-    }
-
-    #[cfg(not(feature = "no-docker"))]
-    fn cwd(&self) -> PathBuf {
-        let prj_dir = self.project_dir.as_ref().unwrap();
-        Path::new("/app").join(prj_dir)
-    }
-
-    #[cfg(feature = "no-docker")]
-    fn cwd(&self) -> PathBuf {
-        let base = self.workspace.path();
-        match self.project_dir.as_ref() {
-            None => base.to_path_buf(),
-            Some(p) => base.join(p),
-        }
-    }
-
-    fn main_abs_path(&self) -> String {
-        let mut d = self.cwd();
-        d.push("src/main.rs");
-
-        d.to_str().unwrap().to_owned()
-    }
-
-    #[cfg(feature = "no-docker")]
-    async fn write_source_code(&self, code: &str) -> Result<()> {
-        let main = self.main_abs_path();
-        fs::write(main, code).context(UnableToWriteFileSnafu)
-    }
-
-    // FIXME: major HACK there should be a much simpler way to copy
-    // a temp file to the docker container. Something similar to
-    // `docker cp` would be great :)
-    #[cfg(not(feature = "no-docker"))]
-    async fn write_source_code(&self, code: &str) -> Result<()> {
-        let mut header = tar::Header::new_gnu();
-        header.set_size(code.len() as u64);
-        header.set_cksum();
-        let data = code.as_bytes();
-        let mut ar = tar::Builder::new(Vec::new());
-        // XXX: the method main_abs_path isn't used here because the header needs to
-        // specify a *relative* path.
-        let path_to_main = Path::new(self.project_dir.as_ref().unwrap()).join("src/main.rs");
-        ar.append_data(&mut header, &path_to_main, data).unwrap();
-
-        let options = Some(UploadToContainerOptions {
-            // NOTE the default path in the Dockerfile is `/app`
-            // if this changes the below path also needs to change.
-            // bollard will not allow empty paths.
-            path: "/app",
-            ..Default::default()
-        });
-        // upload the tar to the container
-        let buf = ar.into_inner().context(UnableToCreateSourceFileSnafu)?;
-
-        self.docker
-            .upload_to_container(&self.id, options, buf.into())
-            .await
-            .context(BollardSnafu)
+          )
+        }),
+    )
+  }
+
+  pub async fn exec_output(
+    &self,
+    cmd: &mut Command,
+  ) -> Result<(String, String)> {
+    let timeout = COMMAND_TIMEOUT;
+    let cmd = cmd.current_dir(self.cwd());
+    let timed_out = match time::timeout(timeout, cmd.output()).await {
+      Ok(Ok(output)) => Ok(output),
+      // failure
+      Ok(e @ Err(_)) => {
+        return e.map(|_| unreachable!()).context(UnableToExecCommandSnafu)
+      }
+      // timeout
+      Err(e) => Err(e),
+    };
+
+    let output = timed_out.context(CommandExecTimedOutSnafu { timeout })?;
+
+    let stdout = String::from_utf8(output.stdout).unwrap();
+    let stderr = String::from_utf8(output.stderr).unwrap();
+    log::info!("{}", stderr);
+
+    Ok((stdout, stderr))
+  }
+
+  async fn cargo_new(&mut self) -> Result<()> {
+    if self.project_dir.is_some() {
+      log::warn!("Attempt to create a second project directory ignored");
+      return Ok(());
     }
 
-    pub async fn permissions(&self, req: &SingleFileRequest) -> Result<ServerResponse> {
-        self.write_source_code(&req.code).await?;
-
-        let mut cmd = self.permissions_command();
-
-        let (stdout, stderr) = self.exec_output(&mut cmd).await?;
-
-        Ok(ServerResponse {
-            // XXX: we'll assume that if there was anything on `stdout`
-            // then there's something successful to report. This does not
-            // mean that `stderr` was empty and all things there shouldn't
-            // go unreported.
-            success: !stdout.trim().is_empty(),
-            stdout,
-            stderr,
-        })
-    }
-
-    pub async fn interpreter(&self, req: &SingleFileRequest) -> Result<ServerResponse> {
-        self.write_source_code(&req.code).await?;
-
-        let mut cmd = self.interpreter_command(req);
-
-        let (stdout, stderr) = self.exec_output(&mut cmd).await?;
-
-        Ok(ServerResponse {
-            // XXX: we'll assume that if there was anything on `stdout`
-            // then there's something successful to report. This does not
-            // mean that `stderr` was empty and all things there shouldn't
-            // go unreported.
-            success: !stdout.trim().is_empty(),
-            stdout,
-            stderr,
-        })
-    }
-
-    // -------------
-    // Commands
-
-    fn permissions_command(&self) -> Command {
-        let cwd = self.cwd();
+    let pwd = DEFAULT_PROJECT_PATH;
 
-        let mut cmd = Command::new("cargo");
-        cmd.args(["--quiet", "aquascope", "permissions"])
-            .current_dir(cwd);
+    let mut cmd = Command::new("cargo");
+    cmd.args(["new", "--bin", pwd, "--quiet"]);
 
-        if cfg!(feature = "no-docker") {
-            let _ = cmd.env("RUST_LOG", "debug").env("RUST_BACKTRACE", "1");
-        }
+    let (output_s, stderr) = self.exec_output(&mut cmd).await?;
 
-        cmd
+    if !stderr.trim().is_empty() {
+      log::error!("{}", stderr);
+      panic!("`cargo new` failed {stderr}");
     }
 
-    fn interpreter_command(&self, req: &SingleFileRequest) -> Command {
-        let cwd = self.cwd();
+    log::debug!("Cargo output {}", output_s);
 
-        let mut cmd = Command::new("cargo");
-        cmd.args(["--quiet", "aquascope"]).current_dir(cwd);
+    self.project_dir = Some(pwd.to_owned());
 
-        if let Some(config) = req.config.as_ref().and_then(|cfg| cfg.as_object()) {
-            if config.contains_key("shouldFail") {
-                cmd.arg("--should-fail");
-            }
-        }
+    Ok(()) // TODO what happens when we can't create the new directory?
+  }
 
-        cmd.arg("interpreter");
-
-        if cfg!(feature = "no-docker") {
-            let _ = cmd.env("RUST_LOG", "debug").env("RUST_BACKTRACE", "1");
-        }
-
-        cmd
+  fn cwd(&self) -> PathBuf {
+    let base = self.workspace.path();
+    match self.project_dir.as_ref() {
+      None => base.to_path_buf(),
+      Some(p) => base.join(p),
     }
-
-    #[cfg(feature = "no-docker")]
-    pub async fn cleanup(self) -> Result<()> {
-        Ok(())
+  }
+
+  fn main_abs_path(&self) -> String {
+    let mut d = self.cwd();
+    d.push("src/main.rs");
+
+    d.to_str().unwrap().to_owned()
+  }
+
+  async fn write_source_code(&self, code: &str) -> Result<()> {
+    let main = self.main_abs_path();
+    fs::write(main, code).context(UnableToWriteFileSnafu)
+  }
+
+  pub async fn permissions(
+    &self,
+    req: &SingleFileRequest,
+  ) -> Result<ServerResponse> {
+    self.write_source_code(&req.code).await?;
+
+    let mut cmd = self.permissions_command()?;
+
+    let (stdout, stderr) = self.exec_output(&mut cmd).await?;
+
+    Ok(ServerResponse {
+      // XXX: we'll assume that if there was anything on `stdout`
+      // then there's something successful to report. This does not
+      // mean that `stderr` was empty and all things there shouldn't
+      // go unreported.
+      success: !stdout.trim().is_empty(),
+      stdout,
+      stderr,
+    })
+  }
+
+  pub async fn interpreter(
+    &self,
+    req: &SingleFileRequest,
+  ) -> Result<ServerResponse> {
+    self.write_source_code(&req.code).await?;
+
+    let mut cmd = self.interpreter_command(req)?;
+
+    let (stdout, stderr) = self.exec_output(&mut cmd).await?;
+
+    Ok(ServerResponse {
+      // XXX: we'll assume that if there was anything on `stdout`
+      // then there's something successful to report. This does not
+      // mean that `stderr` was empty and all things there shouldn't
+      // go unreported.
+      success: !stdout.trim().is_empty(),
+      stdout,
+      stderr,
+    })
+  }
+
+  fn permissions_command(&self) -> Result<Command> {
+    let cwd = self.cwd();
+    let mut cmd = Command::new("cargo");
+    cmd
+      .args(["--quiet", "aquascope", "permissions"])
+      .env("RUST_LOG", "trace")
+      .env("RUST_BACKTRACE", "1")
+      .env("MIRI_SYSROOT", miri_sysroot()?)
+      .current_dir(cwd);
+
+    Ok(cmd)
+  }
+
+  fn interpreter_command(&self, req: &SingleFileRequest) -> Result<Command> {
+    let cwd = self.cwd();
+    let mut cmd = Command::new("cargo");
+    cmd
+      .args(["--quiet", "aquascope"])
+      .current_dir(cwd)
+      .env("RUST_LOG", "debug")
+      .env("RUST_BACKTRACE", "1")
+      .env("MIRI_SYSROOT", miri_sysroot()?);
+
+    if let Some(config) = req.config.as_ref().and_then(|cfg| cfg.as_object()) {
+      if config.contains_key("shouldFail") {
+        cmd.arg("--should-fail");
+      }
     }
 
-    #[cfg(not(feature = "no-docker"))]
-    pub async fn cleanup(mut self) -> Result<()> {
-        self.killed = true;
-        let options: Option<RemoveContainerOptions> = Some(RemoveContainerOptions {
-            force: true,
-            ..Default::default()
-        });
+    cmd.arg("interpreter");
 
-        log::info!("Removing container {}", self.id);
-
-        self.docker
-            .remove_container(&self.id, options)
-            .await
-            .context(BollardSnafu)
-    }
-}
+    Ok(cmd)
+  }
 
-#[cfg(not(feature = "no-docker"))]
-impl Drop for Container {
-    fn drop(&mut self) {
-        if !self.killed {
-            log::warn!(
-                "Dropping container {} without calling Container::cleanup.",
-                self.id
-            );
-        }
-    }
+  pub async fn cleanup(self) -> Result<()> {
+    Ok(())
+  }
 }
 
 #[allow(dead_code)]
 fn full_permissions() -> std::fs::Permissions {
-    PermissionsExt::from_mode(0o777)
-}
-
-impl From<bollard::errors::Error> for Error {
-    fn from(item: bollard::errors::Error) -> Self {
-        Error::Bollard { source: item }
-    }
+  PermissionsExt::from_mode(0o777)
 }
 
 #[cfg(test)]
 mod test {
-    use super::*;
-
-    // HACK taken from the rust-playground:
-    // https://github.com/integer32llc/rust-playground/blob/master/ui/src/sandbox.rs#L1065-L1075
-    //
-    // Limits testing to one function at a time. Ensuring that containers
-    // have their full allotment when my local machine has fewer resources
-    // than the server.
-    fn one_test_at_a_time() -> impl Drop {
-        use lazy_static::lazy_static;
-        use std::sync::Mutex;
-
-        lazy_static! {
-            static ref DOCKER_SINGLETON: Mutex<()> = Default::default();
-        }
-
-        // We can't poison the empty tuple
-        DOCKER_SINGLETON.lock().unwrap_or_else(|e| e.into_inner())
-    }
-
-    #[tokio::test]
-    #[cfg(not(feature = "no-docker"))]
-    async fn container_test() -> Result<()> {
-        let _s = one_test_at_a_time();
-        let docker = Arc::new(Docker::connect_with_local_defaults()?);
-        docker.ping().await?;
-        let container = Container::with_docker(docker, DEFAULT_IMAGE).await?;
-        let mut cmd = Command::new("echo");
-        cmd.arg("hey");
-        let (output, _) = container.exec_output(&mut cmd).await?;
-        container.cleanup().await?;
-        assert_eq!(output, "hey");
-
-        Ok(())
-    }
-
-    #[tokio::test]
-    async fn container_test_new_project() -> Result<()> {
-        let _s = one_test_at_a_time();
-        let code = "fn main() { return 0; }";
-        let mut container = Container::new().await?;
-        container.cargo_new().await.expect("cargo new");
-        assert!(container.project_dir.is_some());
-        container.write_source_code(code).await?;
-        let main_rs = container.main_abs_path();
-        let mut cmd = Command::new("cat");
-        cmd.arg(&main_rs);
-
-        let (output, _) = container.exec_output(&mut cmd).await?;
-        container.cleanup().await?;
-        assert_eq!(output, code);
-
-        Ok(())
-    }
-
-    #[tokio::test]
-    #[cfg(not(feature = "no-docker"))]
-    async fn container_has_timeout() -> Result<()> {
-        let _s = one_test_at_a_time();
-        let code = r#"
-            fn main() {
-                loop {}
-            }
-        "#
-        .to_string();
-        let container = Container::new().await?;
-        let req = SingleFileRequest { code, config: None };
-        let res = container.interpreter(&req).await?;
-
-        container.cleanup().await?;
-
-        assert!(!res.success);
-        assert!(res.stderr.contains("SIGKILL"));
-
-        Ok(())
-    }
-
-    #[tokio::test]
-    #[cfg(not(feature = "no-docker"))]
-    async fn container_has_memory_limit() -> Result<()> {
-        let _s = one_test_at_a_time();
-        let code = r#"
-            fn main() {
-                let gigabyte = 1024 * 1024 * 1024;
-                let mut big = vec![0u8; 1 * gigabyte];
-                for i in &mut big { *i += 1; }
-            }
-        "#
-        .to_string();
-        let container = Container::new().await?;
-        let req = SingleFileRequest { code, config: None };
-        let res = container.interpreter(&req).await?;
-
-        container.cleanup().await?;
-
-        assert!(!res.success);
-        assert!(res.stderr.contains("SIGKILL"));
-
-        Ok(())
-    }
+  use super::*;
+
+  #[tokio::test]
+  async fn container_test_new_project() -> Result<()> {
+    let code = "fn main() { return 0; }";
+    let mut container = Container::new().await?;
+    container.cargo_new().await.expect("cargo new");
+    assert!(container.project_dir.is_some());
+    container.write_source_code(code).await?;
+    let main_rs = container.main_abs_path();
+    let mut cmd = Command::new("cat");
+    cmd.arg(&main_rs);
+
+    let (output, _) = container.exec_output(&mut cmd).await?;
+    container.cleanup().await?;
+    assert_eq!(output, code);
+
+    Ok(())
+  }
 }
diff --git a/crates/aquascope_serve/src/main.rs b/crates/aquascope_serve/src/main.rs
index c16542f68..46d806fd9 100644
--- a/crates/aquascope_serve/src/main.rs
+++ b/crates/aquascope_serve/src/main.rs
@@ -1,9 +1,9 @@
-#![feature(async_closure)]
 #![allow(dead_code)]
+use std::{env, net::SocketAddr};
+
 use serde::{Deserialize, Serialize};
 use serde_json::Value;
 use snafu::prelude::*;
-use std::{env, net::SocketAddr};
 
 const DEFAULT_ADDRESS: &str = "127.0.0.1";
 const DEFAULT_PORT: u16 = 8008;
@@ -12,79 +12,81 @@ mod container;
 mod server;
 
 fn main() {
-    // Default logging is error only, info is useful for a server.
-    let env_logger_config = env_logger::Env::default().default_filter_or("info");
-    env_logger::Builder::from_env(env_logger_config).init();
+  // Default logging is error only, info is useful for a server.
+  let env_logger_config = env_logger::Env::default().default_filter_or("info");
+  env_logger::Builder::from_env(env_logger_config).init();
 
-    // TODO setup the environment
+  let cfg = Config::from_env();
+  assert!(cfg.no_docker);
 
-    let cfg = Config::from_env();
-    server::serve(cfg);
+  log::warn!("The Aquascope server is only used for local debugging. Requests will be processed on your machine!");
+
+  server::serve(cfg);
 }
 
 struct Config {
-    address: String,
-    port: u16,
-    no_docker: bool,
+  address: String,
+  port: u16,
+  no_docker: bool,
 }
 
 #[derive(Debug, Clone, Serialize)]
 struct ErrorJson {
-    error: String,
+  error: String,
 }
 
 impl Config {
-    fn from_env() -> Self {
-        let address =
-            env::var("AQUASCOPE_SERVER_ADDRESS").unwrap_or_else(|_| DEFAULT_ADDRESS.to_owned());
-        let port = env::var("AQUASCOPE_SERVER_PORT")
-            .ok()
-            .and_then(|p| p.parse().ok())
-            .unwrap_or(DEFAULT_PORT);
-        let no_docker = env::var("AQUASCOPE_NO_DOCKER").is_ok();
-        Config {
-            address,
-            port,
-            no_docker,
-        }
+  fn from_env() -> Self {
+    let address = env::var("AQUASCOPE_SERVER_ADDRESS")
+      .unwrap_or_else(|_| DEFAULT_ADDRESS.to_owned());
+    let port = env::var("AQUASCOPE_SERVER_PORT")
+      .ok()
+      .and_then(|p| p.parse().ok())
+      .unwrap_or(DEFAULT_PORT);
+    let no_docker = true;
+    Config {
+      address,
+      port,
+      no_docker,
     }
+  }
 
-    fn socket_address(&self) -> SocketAddr {
-        let a = self.address.parse().expect("Invalid address");
-        SocketAddr::new(a, self.port)
-    }
+  fn socket_address(&self) -> SocketAddr {
+    let a = self.address.parse().expect("Invalid address");
+    SocketAddr::new(a, self.port)
+  }
 }
 
 #[derive(Debug, Clone, Deserialize)]
 pub struct SingleFileRequest {
-    code: String,
-    config: Option<Value>,
+  code: String,
+  config: Option<Value>,
 }
 
 #[derive(Debug, Clone, Serialize)]
 pub struct ServerResponse {
-    success: bool,
-    stdout: String,
-    stderr: String,
+  success: bool,
+  stdout: String,
+  stderr: String,
 }
 
 #[derive(Debug, Snafu)]
 pub enum Error {
-    #[snafu(display("Creating the container failed {source}"))]
-    ContainerCreation { source: container::Error },
-    #[snafu(display("Running permissions analysis failed  {source}"))]
-    Permissions { source: container::Error },
-    #[snafu(display("Running interpreter failed {source}"))]
-    Interpreter { source: container::Error },
-    #[snafu(display("An Unknown error occurred: {msg}"))]
-    Unknown { msg: String },
+  #[snafu(display("Creating the container failed {source}"))]
+  ContainerCreation { source: container::Error },
+  #[snafu(display("Running permissions analysis failed  {source}"))]
+  Permissions { source: container::Error },
+  #[snafu(display("Running interpreter failed {source}"))]
+  Interpreter { source: container::Error },
+  #[snafu(display("An Unknown error occurred: {msg}"))]
+  Unknown { msg: String },
 }
 
 pub type Result<T, E = Error> = ::std::result::Result<T, E>;
 
 impl axum::response::IntoResponse for Error {
-    fn into_response(self) -> axum::response::Response {
-        let body = format!("{self}");
-        (axum::http::StatusCode::INTERNAL_SERVER_ERROR, body).into_response()
-    }
+  fn into_response(self) -> axum::response::Response {
+    let body = format!("{self}");
+    (axum::http::StatusCode::INTERNAL_SERVER_ERROR, body).into_response()
+  }
 }
diff --git a/crates/aquascope_serve/src/server.rs b/crates/aquascope_serve/src/server.rs
index 84b34e36f..43010f72c 100644
--- a/crates/aquascope_serve/src/server.rs
+++ b/crates/aquascope_serve/src/server.rs
@@ -1,100 +1,106 @@
-use crate::{
-    container::{self, Container},
-    Config, ContainerCreationSnafu, Error, ErrorJson, InterpreterSnafu, PermissionsSnafu, Result,
-    ServerResponse, SingleFileRequest,
-};
 use async_trait::async_trait;
 use axum::{
-    extract,
-    handler::Handler,
-    http::{header, Method},
-    response::IntoResponse,
-    routing::{get, post},
-    Router,
+  extract,
+  handler::Handler,
+  http::{header, Method},
+  response::IntoResponse,
+  routing::{get, post},
+  Router,
 };
 use futures::{future::BoxFuture, FutureExt};
 use snafu::{prelude::*, IntoError};
 use tower_http::cors::{self, CorsLayer};
 
+use crate::{
+  container::{self, Container},
+  Config, ContainerCreationSnafu, Error, ErrorJson, InterpreterSnafu,
+  PermissionsSnafu, Result, ServerResponse, SingleFileRequest,
+};
+
 #[tokio::main]
 pub(crate) async fn serve(cfg: Config) {
-    let mut app = Router::new()
-        .fallback(fallback.into_service())
-        .route(
-            "/hi",
-            get(|| async {
-                log::info!("Received Message");
-                "HELLO!"
-            }),
-        )
-        .route("/permissions", post(permissions))
-        .route("/interpreter", post(interpreter));
-
-    app = app.layer({
-        CorsLayer::new()
-            .allow_origin(cors::Any)
-            .allow_headers([header::CONTENT_TYPE])
-            .allow_methods([Method::GET, Method::POST])
-            .allow_credentials(false)
-    });
-
-    if cfg.no_docker {
-        log::warn!("Requests will be processed outside of docker");
-    }
-
-    log::info!("Serving requests on {}:{}", cfg.address, cfg.port);
-
-    axum::Server::bind(&cfg.socket_address())
-        .serve(app.into_make_service())
-        .await
-        .unwrap();
+  let mut app = Router::new()
+    .fallback(fallback.into_service())
+    .route(
+      "/hi",
+      get(|| async {
+        log::info!("Received Message");
+        "HELLO!"
+      }),
+    )
+    .route("/permissions", post(permissions))
+    .route("/interpreter", post(interpreter));
+
+  app = app.layer({
+    CorsLayer::new()
+      .allow_origin(cors::Any)
+      .allow_headers([header::CONTENT_TYPE])
+      .allow_methods([Method::GET, Method::POST])
+      .allow_credentials(false)
+  });
+
+  log::info!("Serving requests on {}:{}", cfg.address, cfg.port);
+
+  axum::Server::bind(&cfg.socket_address())
+    .serve(app.into_make_service())
+    .await
+    .unwrap();
 }
 
 macro_rules! make_single_file_endpoint {
-    ($name:ident, $ectx:path) => {
-        async fn $name(Json(req): Json<SingleFileRequest>) -> Result<Json<ServerResponse>> {
-            log::trace!("Received request for {}", stringify!($name));
-
-            let json = with_container(
-                req,
-                |knt, req| {
-                    async move {
-                        let v = knt.$name(req).await;
-                        if let Err(e) = knt.cleanup().await {
-                            log::warn!("Error cleaning up container: {:?}", e);
-                        }
-                        v
-                    }
-                    .boxed()
-                },
-                $ectx,
-            )
-            .await
-            .map(Json);
-
-            log::debug!("returning JSON {:?}", json);
-
-            json
-        }
-    };
+  ($name:ident, $ectx:path) => {
+    async fn $name(
+      Json(req): Json<SingleFileRequest>,
+    ) -> Result<Json<ServerResponse>> {
+      log::trace!("Received request for {}", stringify!($name));
+
+      let json = with_container(
+        req,
+        |knt, req| {
+          async move {
+            let v = knt.$name(req).await;
+            if let Err(e) = knt.cleanup().await {
+              log::warn!("Error cleaning up container: {:?}", e);
+            }
+            v
+          }
+          .boxed()
+        },
+        $ectx,
+      )
+      .await
+      .map(Json);
+
+      log::debug!("returning JSON {:?}", json);
+
+      json
+    }
+  };
 }
 
 make_single_file_endpoint!(permissions, PermissionsSnafu);
 make_single_file_endpoint!(interpreter, InterpreterSnafu);
 
-async fn with_container<F, Req, Resp, Ctx>(req: Req, f: F, ctx: Ctx) -> Result<Resp, Error>
+async fn with_container<F, Req, Resp, Ctx>(
+  req: Req,
+  f: F,
+  ctx: Ctx,
+) -> Result<Resp, Error>
 where
-    for<'req> F: FnOnce(Container, &'req Req) -> BoxFuture<'req, container::Result<Resp>>,
-    Ctx: IntoError<Error, Source = container::Error>,
+  for<'req> F:
+    FnOnce(Container, &'req Req) -> BoxFuture<'req, container::Result<Resp>>,
+  Ctx: IntoError<Error, Source = container::Error>,
 {
-    let container = Container::new().await.context(ContainerCreationSnafu)?;
-    f(container, &req).await.map(Into::into).context(ctx)
+  let container = Container::new().await.context(ContainerCreationSnafu)?;
+  f(container, &req).await.map(Into::into).context(ctx)
 }
 
 /// Axum handler for any request that fails to match the router routes.
 /// This implementation returns HTTP status code Not Found (404).
-pub async fn fallback(uri: axum::http::Uri) -> impl axum::response::IntoResponse {
-    (axum::http::StatusCode::NOT_FOUND, format!("No route {uri}"))
+pub async fn fallback(
+  uri: axum::http::Uri,
+) -> impl axum::response::IntoResponse {
+  (axum::http::StatusCode::NOT_FOUND, format!("No route {uri}"))
 }
 
 /// This type only exists so that we can recover from the `axum::Json`
@@ -105,30 +111,32 @@ struct Json<T>(T);
 #[async_trait]
 impl<T, B> extract::FromRequest<B> for Json<T>
 where
-    T: serde::de::DeserializeOwned,
-    B: axum::body::HttpBody + Send,
-    B::Data: Send,
-    B::Error: Into<axum::BoxError>,
+  T: serde::de::DeserializeOwned,
+  B: axum::body::HttpBody + Send,
+  B::Data: Send,
+  B::Error: Into<axum::BoxError>,
 {
-    type Rejection = axum::response::Response;
-
-    async fn from_request(req: &mut extract::RequestParts<B>) -> Result<Self, Self::Rejection> {
-        match axum::Json::<T>::from_request(req).await {
-            Ok(v) => Ok(Self(v.0)),
-            Err(e) => {
-                let error = format!("Unable to deserialize request: {e}");
-                Err(axum::Json(ErrorJson { error }).into_response())
-            }
-        }
+  type Rejection = axum::response::Response;
+
+  async fn from_request(
+    req: &mut extract::RequestParts<B>,
+  ) -> Result<Self, Self::Rejection> {
+    match axum::Json::<T>::from_request(req).await {
+      Ok(v) => Ok(Self(v.0)),
+      Err(e) => {
+        let error = format!("Unable to deserialize request: {e}");
+        Err(axum::Json(ErrorJson { error }).into_response())
+      }
     }
+  }
 }
 
 impl<T> IntoResponse for Json<T>
 where
-    T: serde::Serialize + std::fmt::Debug,
+  T: serde::Serialize + std::fmt::Debug,
 {
-    fn into_response(self) -> axum::response::Response {
-        log::trace!("Turning Json<T> into response {:?}", self.0);
-        axum::Json(self.0).into_response()
-    }
+  fn into_response(self) -> axum::response::Response {
+    log::trace!("Turning Json<T> into response {:?}", self.0);
+    axum::Json(self.0).into_response()
+  }
 }
diff --git a/crates/mdbook-aquascope/Cargo.toml b/crates/mdbook-aquascope/Cargo.toml
index b030739b2..dd5783faf 100644
--- a/crates/mdbook-aquascope/Cargo.toml
+++ b/crates/mdbook-aquascope/Cargo.toml
@@ -23,7 +23,7 @@ clap = { version = "=4.3.24", features = ["derive"] }
 mdbook-preprocessor-utils = "0.2.0"
 nom = "7"
 nom_locate = "4"
-anyhow = "1"
+anyhow.workspace = true
 tempfile = "3"
 serde_json = "1"
 serde = { workspace = true }
@@ -41,5 +41,5 @@ mdbook-aquascope = { path = ".", features = ["dev"] }
 maplit = "1.0"
 
 [build-dependencies]
-anyhow = "1"
-mdbook-preprocessor-utils = "0.2.0"
\ No newline at end of file
+anyhow.workspace = true
+mdbook-preprocessor-utils = "0.2.0"
diff --git a/crates/mdbook-aquascope/src/cache.rs b/crates/mdbook-aquascope/src/cache.rs
index c79a4efad..80220dcda 100644
--- a/crates/mdbook-aquascope/src/cache.rs
+++ b/crates/mdbook-aquascope/src/cache.rs
@@ -33,6 +33,7 @@ impl<K: Hash, V: Serialize + DeserializeOwned> Cache<K, V> {
       .read(true)
       .write(true)
       .create(true)
+      .truncate(false)
       .open(CACHE_PATH)?;
     let cache = if cache_file.metadata()?.len() == 0 {
       HashMap::new()
diff --git a/deploy/ping.sh b/deploy/ping.sh
deleted file mode 100644
index 157ee2ea6..000000000
--- a/deploy/ping.sh
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/bash
-
-echo From_GHActions > ~/testing.txt
diff --git a/deploy/playground.service b/deploy/playground.service
deleted file mode 100644
index 09248bc5c..000000000
--- a/deploy/playground.service
+++ /dev/null
@@ -1,8 +0,0 @@
-[Unit]
-Description=Aquascope Playground
-
-[Service]
-Environment=RUST_LOG=warn
-WorkingDirectory=/home/gh-actions/artifacts
-User=gh-actions
-ExecStart=/home/gh-actions/artifacts/aquascope_serve
diff --git a/deploy/update.sh b/deploy/update.sh
deleted file mode 100644
index caabd1473..000000000
--- a/deploy/update.sh
+++ /dev/null
@@ -1,37 +0,0 @@
-#!/bin/bash
-
-# NOTE: this file was inspired by the Rust Playground deployment:
-# https://github.com/rust-lang/rust-playground/blob/main/deployment/update.sh
-
-set -euv -o pipefail
-
-ROOT="/home/$USER"
-ARTIFACT_DIR="$ROOT/artifacts"
-BINARY_PATH="$ARTIFACT_DIR/aquascope_serve"
-IMAGE_PATH="$ARTIFACT_DIR/image.tar"
-ZIP="$ROOT/artifacts.zip"
-ZIP_STASH="$ROOT/old/artifacts.zip"
-
-# Do all work from home directory
-cd "${ROOT}"
-
-# Get the binary's hash so we know if it has changed
-PREVIOUS_BINARY_HASH=""
-if [[ -f "${BINARY_PATH}" ]]; then
-  PREVIOUS_BINARY_HASH=$(md5sum "${BINARY_PATH}")
-fi
-
-# Unzip archive files if they exist
-if [[ -f "${ZIP}" ]]; then
-    unzip -o "${ZIP}" -d "${ARTIFACT_DIR}"
-    docker load -i "${IMAGE_PATH}"
-    chmod +x "${BINARY_PATH}"
-    mv "${ZIP}" "${ZIP_STASH}"
-fi
-
-# Restart to get new server binary
-if [[ -z "${PREVIOUS_BINARY_HASH}" ]] || ! md5sum -c <(echo "${PREVIOUS_BINARY_HASH}") --status; then
-    sudo service playground stop || true
-    sudo service playground start
-    echo "Playground service restarted"
-fi
diff --git a/flake.nix b/flake.nix
index 539fc6cd4..3c2aad8a6 100644
--- a/flake.nix
+++ b/flake.nix
@@ -18,9 +18,10 @@
     depotjs = depot-js.packages.${system}.default;
 
     ci-check = pkgs.writeScriptBin "ci-check" ''
-      cargo fmt --check
-      cargo insta test -- --skip container_
-      cd crates/mdbook-aquascope/test-book && mdbook build && cd ../../../
+      cargo fmt --check &&
+      cargo clippy -- -D warnings &&
+      cargo insta test &&
+      cd crates/mdbook-aquascope/test-book && mdbook build && cd ../../../ &&
       cd frontend && depot test && cd ..
     '';
 
diff --git a/frontend/packages/aquascope-editor/src/editor-utils/boundaries.tsx b/frontend/packages/aquascope-editor/src/editor-utils/boundaries.tsx
index b4e11448d..23a65fae0 100644
--- a/frontend/packages/aquascope-editor/src/editor-utils/boundaries.tsx
+++ b/frontend/packages/aquascope-editor/src/editor-utils/boundaries.tsx
@@ -24,62 +24,6 @@ import {
   writeChar
 } from "./misc.js";
 
-// FIXME: the tooltips are not currently being used. The tooltips
-// provided by CM6 aren't expressive enough for what we want.
-// export const copiedValueHover = hoverTooltip(
-//   (_view, pos: number, side: number) => {
-//     let copyPoints = Array.from(
-//       document.querySelectorAll<HTMLElement>(".copied-tip")
-//     );
-
-//     let sPos = pos.toString();
-//     let hovered = copyPoints.find(s => s.dataset.bufferPos == sPos);
-//     if (hovered == undefined || hovered == null || side >= 0) {
-//       return null;
-//     }
-
-//     let copiedPerm = hovered.textContent!;
-//     return {
-//       pos: pos,
-//       above: true,
-//       arrow: true,
-//       create(_view) {
-//         let dom = document.createElement("div");
-//         dom.textContent = "Value was copied: creating 'O' permission";
-//         dom.classList.add("cm-tooltip-cursor");
-//         return { dom };
-//       },
-//     };
-//   }
-// );
-
-// export const insufficientTypeHover = hoverTooltip(
-//   (_view, pos: number, side: number) => {
-//     let copyPoints = Array.from(
-//       document.querySelectorAll<HTMLElement>(".insufficient-type-tip")
-//     );
-
-//     let sPos = pos.toString();
-//     let hovered = copyPoints.find(s => s.dataset.bufferPos == sPos);
-//     if (hovered == undefined || hovered == null || side >= 0) {
-//       return null;
-//     }
-
-//     let perm = hovered.textContent!;
-//     return {
-//       pos: pos,
-//       above: true,
-//       arrow: true,
-//       create(_view) {
-//         let dom = document.createElement("div");
-//         dom.textContent = `Declared type does not allow for permission '${perm}'`;
-//         dom.classList.add("cm-tooltip-cursor");
-//         return { dom };
-//       },
-//     };
-//   }
-// );
-
 interface PermCharProps {
   content: PermLetter;
   names: string[];
@@ -93,8 +37,8 @@ let PermChar = ({ content, names, act, showit, hideit }: PermCharProps) => {
   name = name.charAt(0).toUpperCase() + name.slice(1);
   let title = `${name} permission is expected, `;
   title += act
-    ? "and the path has the permission."
-    : "but the path does not have the permission.";
+    ? "and the place has the permission."
+    : "but the place does not have the permission.";
   return (
     <div
       className={classNames(...names, { missing: !act })}
@@ -115,14 +59,14 @@ let PermStack = ({
   facts: AnalysisFacts;
   boundary: PermissionsBoundary;
 }) => {
-  const data = boundary.actual;
+  const data = boundary.data;
 
   let allIcons: (PermCharProps & { exp: boolean })[] = [
     {
       content: readChar,
       names: ["perm", "read"],
       exp: boundary.expected.read,
-      act: data.permissions.read,
+      act: boundary.actual.read,
       showit: () => {
         showLoanRegion(facts, data.loan_read_refined, ["read"]);
         showMoveRegion(facts, data.path_moved, ["read"]);
@@ -136,7 +80,7 @@ let PermStack = ({
       content: writeChar,
       names: ["perm", "write"],
       exp: boundary.expected.write,
-      act: data.permissions.write,
+      act: boundary.actual.write,
       showit: () => {
         showLoanRegion(facts, data.loan_write_refined, ["write"]);
         showMoveRegion(facts, data.path_moved, ["write"]);
@@ -150,7 +94,7 @@ let PermStack = ({
       content: ownChar,
       names: ["perm", "own"],
       exp: boundary.expected.drop,
-      act: data.permissions.drop,
+      act: boundary.actual.drop,
       showit: () => {
         showLoanRegion(facts, data.loan_drop_refined, ["own"]);
         showMoveRegion(facts, data.path_moved, ["own"]);
@@ -164,7 +108,7 @@ let PermStack = ({
       content: flowChar,
       names: ["perm", "flow"],
       exp: boundary.expecting_flow !== undefined,
-      act: !boundary.expecting_flow?.is_violation ?? false,
+      act: !(boundary.expecting_flow?.is_violation ?? false),
       showit: () => void null,
       hideit: () => void null
     }
diff --git a/frontend/packages/aquascope-editor/src/editor-utils/interpreter.tsx b/frontend/packages/aquascope-editor/src/editor-utils/interpreter.tsx
index 678dda482..96b20281f 100644
--- a/frontend/packages/aquascope-editor/src/editor-utils/interpreter.tsx
+++ b/frontend/packages/aquascope-editor/src/editor-utils/interpreter.tsx
@@ -118,7 +118,8 @@ let read_unique = (unique: MAdt): MAdt => {
 
 let read_vec = (vec: MAdt): MAdt => {
   let raw_vec = read_field(vec, "buf");
-  let unique = read_field(raw_vec, "ptr");
+  let raw_vec_inner = read_field(raw_vec, "inner");
+  let unique = read_field(raw_vec_inner, "ptr");
   return read_unique(unique);
 };
 
diff --git a/frontend/packages/aquascope-editor/src/editor-utils/stepper.tsx b/frontend/packages/aquascope-editor/src/editor-utils/stepper.tsx
index c686eb149..18043f991 100644
--- a/frontend/packages/aquascope-editor/src/editor-utils/stepper.tsx
+++ b/frontend/packages/aquascope-editor/src/editor-utils/stepper.tsx
@@ -56,14 +56,14 @@ let PermChar = ({
       return perm.step.value ? (
         <div
           className="perm-diff-present"
-          title={`Path had ${kind} permissions before the preceding line, and that didn't change after this line.`}
+          title={`Place had ${kind} permissions before the preceding line, and that didn't change after this line.`}
         >
           <Perm>{perm.perm}</Perm>
         </div>
       ) : (
         <div
           className="perm-diff-none"
-          title={`Path did not have ${kind} permissions before the preceding line, and that didn't change after this line.`}
+          title={`Place did not have ${kind} permissions before the preceding line, and that didn't change after this line.`}
         >
           <Perm>‒</Perm>
         </div>
@@ -72,7 +72,7 @@ let PermChar = ({
       return (
         <div
           className="perm-diff-sub-container"
-          title={`Path had ${kind} permissions before the preceding line, and lost it after this line.`}
+          title={`Place had ${kind} permissions before the preceding line, and lost it after this line.`}
         >
           <div className="perm-diff-sub" />
           <Perm>{perm.perm}</Perm>
@@ -81,7 +81,7 @@ let PermChar = ({
     } /* perm.step.type === "High" */ else {
       return (
         <div
-          title={`Path did not have ${kind} permissions before the preceding line, and gained it after this line.`}
+          title={`Place did not have ${kind} permissions before the preceding line, and gained it after this line.`}
         >
           <span className="perm-diff-add">+</span>
           <Perm>{perm.perm}</Perm>
@@ -146,12 +146,12 @@ let PermDiffRow = ({
         {
           value: { type: "High", value: 0 },
           icon: "sign-out",
-          desc: "Path is moved here"
+          desc: "Place is moved here"
         },
         {
           value: { type: "Low" },
           icon: "recycle",
-          desc: "Path is re-initialized after move here"
+          desc: "Place is re-initialized after move here"
         }
       ]
     },
@@ -161,12 +161,12 @@ let PermDiffRow = ({
         {
           value: { type: "High", value: 0 },
           icon: "arrow-right",
-          desc: "Path is borrowed here"
+          desc: "Place is borrowed here"
         },
         {
           value: { type: "Low" },
           icon: "rotate-left",
-          desc: "Borrow on path is dropped here"
+          desc: "Borrow on place is dropped here"
         }
       ]
     },
@@ -176,12 +176,12 @@ let PermDiffRow = ({
         {
           value: { type: "High", value: 0 },
           icon: "arrow-right",
-          desc: "Path is borrowed here"
+          desc: "Place is borrowed here"
         },
         {
           value: { type: "Low" },
           icon: "rotate-left",
-          desc: "Borrow on path is no longer used here"
+          desc: "Borrow on place is no longer used here"
         }
       ]
     },
@@ -191,12 +191,12 @@ let PermDiffRow = ({
         {
           value: { type: "High", value: 0 },
           icon: "level-up",
-          desc: "Path is initialized here"
+          desc: "Place is initialized here"
         },
         {
           value: { type: "Low" },
           icon: "level-down",
-          desc: "Path is no longer used here"
+          desc: "Place is no longer used here"
         }
       ]
     },
@@ -206,12 +206,12 @@ let PermDiffRow = ({
         {
           value: { type: "High", value: 0 },
           icon: "sign-out",
-          desc: "Path contains uninitialized data"
+          desc: "Place contains uninitialized data"
         },
         {
           value: { type: "Low" },
           icon: "recycle",
-          desc: "Path data is initialized after move here"
+          desc: "Place data is initialized after move here"
         }
       ]
     }
diff --git a/rust-toolchain.toml b/rust-toolchain.toml
index 220c5ac87..be943aa03 100644
--- a/rust-toolchain.toml
+++ b/rust-toolchain.toml
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2023-08-25"
+channel = "nightly-2024-12-15"
 components = ["rust-src", "rustc-dev", "llvm-tools-preview", "miri"]
diff --git a/scripts/versioning.ros b/scripts/versioning.ros
deleted file mode 100755
index d74848d92..000000000
--- a/scripts/versioning.ros
+++ /dev/null
@@ -1,115 +0,0 @@
-#!/bin/sh
-#|-*- mode:lisp -*-|#
-#|
-exec ros -Q -- $0 "$@"
-|#
-(progn ;;init forms
-  (ros:ensure-asdf)
-  #+quicklisp(ql:quickload '("cl-toml") :silent t)
-  )
-
-(defpackage :ros.script.versioning.3891266390
-  (:use :cl))
-(in-package :ros.script.versioning.3891266390)
-
-
-(defstruct semver major minor patch)
-
-(defparameter *tomls* #P"../crates/**/Cargo.toml")
-(defparameter *no-publish-version*
-  (make-semver :major 0 :minor 1 :patch 0))
-(defparameter *file-warning*
-  "# This file is automatically managed by scripts/versioning.ros")
-
-(defmethod semver-lt ((lhs semver) (rhs semver))
-  (or (< (semver-major lhs) (semver-major rhs))
-      (and (= (semver-major lhs) (semver-major rhs))
-           (< (semver-minor lhs) (semver-minor rhs)))
-      (and (= (semver-major lhs) (semver-major rhs))
-           (= (semver-minor lhs) (semver-minor rhs))
-           (< (semver-patch lhs) (semver-patch rhs)))))
-
-(defmethod semver-encode ((v semver))
-  (format nil "~d.~d.~d"
-          (semver-major v) (semver-minor v) (semver-patch v)))
-
-(defun semver-parse (s)
-  (multiple-value-bind (mj mn p)
-      (values-list (uiop:split-string s :separator "."))
-    (make-semver :major (parse-integer
-                         (string-left-trim '(#\v #\V) mj))
-                 :minor (parse-integer mn)
-                 :patch (parse-integer p))))
-
-(defun toml-published? (toml)
-  (not (eq (gethash "publish"
-                    (gethash "package" toml))
-           'cl-toml:false)))
-
-(defmacro toml-version (toml)
-  `(gethash "version" (gethash "package" ,toml)))
-
-(defun toml-published-version (toml)
-  (and (toml-published? toml)
-       (semver-parse (toml-version toml))))
-
-(defun get-synced-version ()
-  (let ((versions
-          (remove nil
-                  (loop for fn in (directory *tomls*)
-                        collect
-                        (toml-published-version (cl-toml:parse-file fn))))))
-    (and (every #'equalp versions (rest versions))
-         (car versions))))
-
-(defun semver-increment-synced (current)
-  (declare (ignore current))
-  (error "UNIMPLEMENTED"))
-
-(defun assert-update (&optional previous)
-  (let* ((version (get-synced-version)))
-    (unless (and version
-         (or (not previous)
-             (semver-lt (semver-parse previous) version)))
-      (error (format nil "passed previous version: ~a is invalid" previous)))))
-
-(defun assert-current (v)
-  (let ((version (get-synced-version))
-        (s (semver-parse v)))
-    (unless (and version s (equalp version s))
-      (error "version invalid"))))
-
-(defun print-published ()
-  (dolist (fn (directory *tomls*))
-    (when (toml-published? (cl-toml:parse-file fn))
-      (print fn))))
-
-(defun update-to (v)
-  (let ((sv (typecase v
-              (string (semver-parse v))
-              (semver v))))
-    (dolist (fn (directory *tomls*))
-      (let* ((toml (cl-toml:parse-file fn)))
-        (setf (toml-version toml)
-              (semver-encode
-               (if (toml-published? toml)
-                   sv
-                   *no-publish-version*)))
-        (with-open-file (fout fn :direction :output
-                                 :if-exists :supersede)
-          (write-line *file-warning* fout)
-          (cl-toml:encode toml fout))))))
-
-(defun main (mode &rest argv)
-  (handler-case (cond ((string-equal mode "check") (assert-update (car argv)))
-                      ((string-equal mode "equal") (assert-current (car argv)))
-                      ((string-equal mode "published") (print-published))
-                      ((string-equal mode "set") (update-to (car argv)))
-                      ((string-equal mode "inc")
-                       (update-to (semver-increment-synced
-                                   (read-from-string (car argv)))))
-                      (t nil))
-    (error (c)
-      (format t "ERR: ~a" c)
-      (uiop:quit 1))))
-;;; vim: set ft=lisp lisp:


Test patch:
diff --git a/crates/aquascope/src/test_utils.rs b/crates/aquascope/src/test_utils.rs
index 7727dc0d0..2af64fc14 100644
--- a/crates/aquascope/src/test_utils.rs
+++ b/crates/aquascope/src/test_utils.rs
@@ -1,12 +1,12 @@
 use std::{
   collections::HashMap, env, fs, io, panic, path::Path, process::Command,
+  sync::Arc,
 };
 
 use anyhow::{bail, Context, Result};
 use fluid_let::fluid_set;
 use itertools::Itertools;
 use rustc_borrowck::consumers::BodyWithBorrowckFacts;
-use rustc_errors::Handler;
 use rustc_hir::BodyId;
 use rustc_middle::{
   mir::{Rvalue, StatementKind},
@@ -34,7 +34,7 @@ use crate::{
     },
     AquascopeAnalysis,
   },
-  errors::{self, silent_emitter::SilentEmitter},
+  errors::{self, silent::silent_session},
   interpreter::{self, MTrace},
 };
 
@@ -48,8 +48,8 @@ impl FileLoader for StringLoader {
     Ok(self.0.clone())
   }
 
-  fn read_binary_file(&self, path: &Path) -> io::Result<Vec<u8>> {
-    fs::read(path)
+  fn read_binary_file(&self, path: &Path) -> io::Result<Arc<[u8]>> {
+    fs::read(path).map(Into::into)
   }
 }
 
@@ -271,8 +271,9 @@ pub fn test_refinements_in_file(path: &Path) {
 
           let path = ctxt.place_to_path(&place);
           let point = ctxt.location_to_point(loc);
-          let computed_perms =
-            ctxt.permissions_data_at_point(path, point).permissions;
+          let computed_perms = ctxt
+            .permissions_data_at_point(path, point)
+            .permissions_ignore_liveness();
 
           assert!(
             (*expected_perms == computed_perms),
@@ -462,7 +463,7 @@ pub fn run_in_dir(
 
 pub fn for_each_body<'tcx>(
   tcx: TyCtxt<'tcx>,
-  mut f: impl FnMut(BodyId, &BodyWithBorrowckFacts<'tcx>),
+  mut f: impl FnMut(BodyId, &'tcx BodyWithBorrowckFacts<'tcx>),
 ) {
   find_bodies(tcx).into_iter().for_each(|(_, body_id)| {
     let def_id = tcx.hir().body_owner_def_id(body_id);
@@ -523,14 +524,7 @@ where
   Cb: FnOnce(TyCtxt<'_>),
 {
   fn config(&mut self, config: &mut rustc_interface::Config) {
-    config.parse_sess_created = Some(Box::new(|sess| {
-      // Create a new emitter writer which consumes *silently* all
-      // errors. There most certainly is a *better* way to do this,
-      // if you, the reader, know what that is, please open an issue :)
-      let handler = Handler::with_emitter(Box::new(SilentEmitter));
-      sess.span_diagnostic = handler;
-    }));
-
+    config.psess_created = Some(silent_session());
     config.override_queries = Some(if self.is_interpreter {
       crate::interpreter::override_queries
     } else {
@@ -538,16 +532,16 @@ where
     });
   }
 
-  fn after_expansion<'tcx>(
+  fn after_analysis<'tcx>(
     &mut self,
     _compiler: &rustc_interface::interface::Compiler,
-    queries: &'tcx rustc_interface::Queries<'tcx>,
+    tcx: TyCtxt<'tcx>,
   ) -> rustc_driver::Compilation {
     errors::initialize_error_tracking();
-    queries.global_ctxt().unwrap().enter(|tcx| {
-      let callback = self.callback.take().unwrap();
-      callback(tcx);
-    });
+
+    let callback = self.callback.take().unwrap();
+    callback(tcx);
+
     rustc_driver::Compilation::Stop
   }
 }
diff --git a/crates/aquascope/tests/boundaries.rs b/crates/aquascope/tests/boundaries.rs
index 7b2de7935..09b35d981 100644
--- a/crates/aquascope/tests/boundaries.rs
+++ b/crates/aquascope/tests/boundaries.rs
@@ -1,3 +1,5 @@
+#![feature(rustc_private)]
+
 use aquascope::test_utils;
 
 #[test_log::test]
diff --git a/crates/aquascope/tests/boundaries/struct_udpate.test b/crates/aquascope/tests/boundaries/struct_udpate.test
new file mode 100644
index 000000000..6be5df0ad
--- /dev/null
+++ b/crates/aquascope/tests/boundaries/struct_udpate.test
@@ -0,0 +1,12 @@
+struct User {
+    name : String,
+    age : i32,
+}
+
+fn main() {
+    let mut a = User { name: String::from("Jeff"), age: 2 };
+    a.age += 1;
+    let b = User { age: 1, ..a };
+    a.age += 1;
+    println!("{} {}", b.name, b.age);
+}
diff --git a/crates/aquascope/tests/interpreter.rs b/crates/aquascope/tests/interpreter.rs
index 7c1605101..3dafbc46d 100644
--- a/crates/aquascope/tests/interpreter.rs
+++ b/crates/aquascope/tests/interpreter.rs
@@ -1,3 +1,5 @@
+#![feature(rustc_private)]
+
 use aquascope::test_utils;
 
 #[test_log::test]
diff --git a/crates/aquascope/tests/permissions.rs b/crates/aquascope/tests/permissions.rs
index 742cf261f..650683057 100644
--- a/crates/aquascope/tests/permissions.rs
+++ b/crates/aquascope/tests/permissions.rs
@@ -1,3 +1,5 @@
+#![feature(rustc_private)]
+
 use aquascope::test_utils;
 
 #[test_log::test]
diff --git a/crates/aquascope/tests/snapshots/boundaries__bar@coerced_0.test.snap b/crates/aquascope/tests/snapshots/boundaries__bar@coerced_0.test.snap
index 3484ce3f6..189564d8a 100644
--- a/crates/aquascope/tests/snapshots/boundaries__bar@coerced_0.test.snap
+++ b/crates/aquascope/tests/snapshots/boundaries__bar@coerced_0.test.snap
@@ -10,15 +10,15 @@ description: bar@coerced_0.test
     write: true
     drop: false
   actual:
+    read: true
+    write: true
+    drop: true
+  data:
     type_droppable: true
     type_writeable: true
     type_copyable: false
     is_live: true
     path_uninitialized: false
-    permissions:
-      read: true
-      write: true
-      drop: true
 - location:
     line: 3
     column: 29
@@ -27,15 +27,15 @@ description: bar@coerced_0.test
     write: true
     drop: false
   actual:
+    read: true
+    write: true
+    drop: false
+  data:
     type_droppable: false
     type_writeable: true
     type_copyable: false
     is_live: true
     path_uninitialized: false
-    permissions:
-      read: true
-      write: true
-      drop: false
 - location:
     line: 4
     column: 9
@@ -44,15 +44,15 @@ description: bar@coerced_0.test
     write: true
     drop: false
   actual:
+    read: true
+    write: true
+    drop: false
+  data:
     type_droppable: false
     type_writeable: true
     type_copyable: false
     is_live: true
     path_uninitialized: false
-    permissions:
-      read: true
-      write: true
-      drop: false
 - location:
     line: 5
     column: 3
@@ -61,13 +61,12 @@ description: bar@coerced_0.test
     write: true
     drop: false
   actual:
+    read: true
+    write: true
+    drop: false
+  data:
     type_droppable: false
     type_writeable: true
     type_copyable: false
     is_live: true
     path_uninitialized: false
-    permissions:
-      read: true
-      write: true
-      drop: false
-
diff --git a/crates/aquascope/tests/snapshots/boundaries__foo@mut_assign.test.snap b/crates/aquascope/tests/snapshots/boundaries__foo@mut_assign.test.snap
index 5687cbcc4..53e2d59ab 100644
--- a/crates/aquascope/tests/snapshots/boundaries__foo@mut_assign.test.snap
+++ b/crates/aquascope/tests/snapshots/boundaries__foo@mut_assign.test.snap
@@ -10,13 +10,12 @@ description: foo@mut_assign.test
     write: true
     drop: false
   actual:
+    read: true
+    write: true
+    drop: false
+  data:
     type_droppable: false
     type_writeable: true
     type_copyable: false
     is_live: true
     path_uninitialized: false
-    permissions:
-      read: true
-      write: true
-      drop: false
-
diff --git a/crates/aquascope/tests/snapshots/boundaries__get_first@type-driven-flows.test.snap b/crates/aquascope/tests/snapshots/boundaries__get_first@type-driven-flows.test.snap
index ab3957700..7dbae6622 100644
--- a/crates/aquascope/tests/snapshots/boundaries__get_first@type-driven-flows.test.snap
+++ b/crates/aquascope/tests/snapshots/boundaries__get_first@type-driven-flows.test.snap
@@ -10,15 +10,15 @@ description: get_first@type-driven-flows.test
     write: false
     drop: false
   actual:
+    read: true
+    write: false
+    drop: false
+  data:
     type_droppable: false
     type_writeable: false
     type_copyable: false
     is_live: true
     path_uninitialized: false
-    permissions:
-      read: true
-      write: false
-      drop: false
   expecting_flow:
     is_violation: false
     flow_context:
@@ -29,7 +29,7 @@ description: get_first@type-driven-flows.test
         line: 16
         column: 20
       filename:
-        private: 0
+        private_use_as_methods_instead: 0
     kind: Ok
 - location:
     line: 17
@@ -39,15 +39,15 @@ description: get_first@type-driven-flows.test
     write: false
     drop: false
   actual:
+    read: true
+    write: false
+    drop: false
+  data:
     type_droppable: false
     type_writeable: false
     type_copyable: true
     is_live: true
     path_uninitialized: false
-    permissions:
-      read: true
-      write: false
-      drop: false
   expecting_flow:
     is_violation: false
     flow_context:
@@ -58,6 +58,5 @@ description: get_first@type-driven-flows.test
         line: 17
         column: 7
       filename:
-        private: 0
+        private_use_as_methods_instead: 0
     kind: Ok
-
diff --git a/crates/aquascope/tests/snapshots/boundaries__get_first_constrained@type-driven-flows.test.snap b/crates/aquascope/tests/snapshots/boundaries__get_first_constrained@type-driven-flows.test.snap
index 2ca6d899e..ff2b1c716 100644
--- a/crates/aquascope/tests/snapshots/boundaries__get_first_constrained@type-driven-flows.test.snap
+++ b/crates/aquascope/tests/snapshots/boundaries__get_first_constrained@type-driven-flows.test.snap
@@ -10,15 +10,15 @@ description: get_first_constrained@type-driven-flows.test
     write: false
     drop: false
   actual:
+    read: true
+    write: false
+    drop: false
+  data:
     type_droppable: false
     type_writeable: false
     type_copyable: false
     is_live: true
     path_uninitialized: false
-    permissions:
-      read: true
-      write: false
-      drop: false
 - location:
     line: 28
     column: 2
@@ -27,15 +27,15 @@ description: get_first_constrained@type-driven-flows.test
     write: false
     drop: false
   actual:
+    read: true
+    write: false
+    drop: false
+  data:
     type_droppable: false
     type_writeable: false
     type_copyable: true
     is_live: true
     path_uninitialized: false
-    permissions:
-      read: true
-      write: false
-      drop: false
   expecting_flow:
     is_violation: false
     flow_context:
@@ -46,6 +46,5 @@ description: get_first_constrained@type-driven-flows.test
         line: 28
         column: 7
       filename:
-        private: 0
+        private_use_as_methods_instead: 0
     kind: Ok
-
diff --git a/crates/aquascope/tests/snapshots/boundaries__get_first_specified@type-driven-flows.test.snap b/crates/aquascope/tests/snapshots/boundaries__get_first_specified@type-driven-flows.test.snap
index c999bc2d8..36c3e20b9 100644
--- a/crates/aquascope/tests/snapshots/boundaries__get_first_specified@type-driven-flows.test.snap
+++ b/crates/aquascope/tests/snapshots/boundaries__get_first_specified@type-driven-flows.test.snap
@@ -10,15 +10,15 @@ description: get_first_specified@type-driven-flows.test
     write: false
     drop: false
   actual:
+    read: true
+    write: false
+    drop: false
+  data:
     type_droppable: false
     type_writeable: false
     type_copyable: false
     is_live: true
     path_uninitialized: false
-    permissions:
-      read: true
-      write: false
-      drop: false
   expecting_flow:
     is_violation: false
     flow_context:
@@ -29,7 +29,7 @@ description: get_first_specified@type-driven-flows.test
         line: 21
         column: 20
       filename:
-        private: 0
+        private_use_as_methods_instead: 0
     kind: Ok
 - location:
     line: 22
@@ -39,15 +39,15 @@ description: get_first_specified@type-driven-flows.test
     write: false
     drop: false
   actual:
+    read: true
+    write: false
+    drop: false
+  data:
     type_droppable: false
     type_writeable: false
     type_copyable: true
     is_live: true
     path_uninitialized: false
-    permissions:
-      read: true
-      write: false
-      drop: false
   expecting_flow:
     is_violation: false
     flow_context:
@@ -58,6 +58,5 @@ description: get_first_specified@type-driven-flows.test
         line: 22
         column: 7
       filename:
-        private: 0
+        private_use_as_methods_instead: 0
     kind: Ok
-
diff --git a/crates/aquascope/tests/snapshots/boundaries__main@assignop_path_resolution.test.snap b/crates/aquascope/tests/snapshots/boundaries__main@assignop_path_resolution.test.snap
index 2c52c5f48..475e2aa7d 100644
--- a/crates/aquascope/tests/snapshots/boundaries__main@assignop_path_resolution.test.snap
+++ b/crates/aquascope/tests/snapshots/boundaries__main@assignop_path_resolution.test.snap
@@ -10,15 +10,15 @@ description: main@assignop_path_resolution.test
     write: false
     drop: false
   actual:
+    read: true
+    write: true
+    drop: true
+  data:
     type_droppable: true
     type_writeable: true
     type_copyable: true
     is_live: true
     path_uninitialized: false
-    permissions:
-      read: true
-      write: true
-      drop: true
 - location:
     line: 7
     column: 10
@@ -27,15 +27,15 @@ description: main@assignop_path_resolution.test
     write: false
     drop: false
   actual:
+    read: true
+    write: false
+    drop: false
+  data:
     type_droppable: false
     type_writeable: false
     type_copyable: true
     is_live: true
     path_uninitialized: false
-    permissions:
-      read: true
-      write: false
-      drop: false
 - location:
     line: 8
     column: 2
@@ -44,15 +44,15 @@ description: main@assignop_path_resolution.test
     write: true
     drop: false
   actual:
+    read: true
+    write: true
+    drop: true
+  data:
     type_droppable: true
     type_writeable: true
     type_copyable: true
-    is_live: true
+    is_live: false
     path_uninitialized: false
-    permissions:
-      read: true
-      write: true
-      drop: true
 - location:
     line: 8
     column: 7
@@ -61,6 +61,10 @@ description: main@assignop_path_resolution.test
     write: false
     drop: false
   actual:
+    read: true
+    write: false
+    drop: false
+  data:
     type_droppable: true
     type_writeable: true
     type_copyable: true
@@ -68,10 +72,6 @@ description: main@assignop_path_resolution.test
     path_uninitialized: false
     loan_write_refined: 0
     loan_drop_refined: 0
-    permissions:
-      read: true
-      write: false
-      drop: false
 - location:
     line: 8
     column: 11
@@ -80,15 +80,15 @@ description: main@assignop_path_resolution.test
     write: false
     drop: false
   actual:
+    read: true
+    write: false
+    drop: true
+  data:
     type_droppable: true
     type_writeable: false
     type_copyable: true
     is_live: true
     path_uninitialized: false
-    permissions:
-      read: true
-      write: false
-      drop: true
 - location:
     line: 8
     column: 15
@@ -97,13 +97,12 @@ description: main@assignop_path_resolution.test
     write: false
     drop: false
   actual:
+    read: true
+    write: false
+    drop: false
+  data:
     type_droppable: false
     type_writeable: false
     type_copyable: true
     is_live: true
     path_uninitialized: false
-    permissions:
-      read: true
-      write: false
-      drop: false
-
diff --git a/crates/aquascope/tests/snapshots/boundaries__main@closure_0.test.snap b/crates/aquascope/tests/snapshots/boundaries__main@closure_0.test.snap
index f6881d1a6..9e9f71dd3 100644
--- a/crates/aquascope/tests/snapshots/boundaries__main@closure_0.test.snap
+++ b/crates/aquascope/tests/snapshots/boundaries__main@closure_0.test.snap
@@ -10,15 +10,15 @@ description: main@closure_0.test
     write: true
     drop: false
   actual:
+    read: true
+    write: true
+    drop: true
+  data:
     type_droppable: true
     type_writeable: true
     type_copyable: false
     is_live: true
     path_uninitialized: false
-    permissions:
-      read: true
-      write: true
-      drop: true
 - location:
     line: 6
     column: 2
@@ -27,15 +27,15 @@ description: main@closure_0.test
     write: true
     drop: false
   actual:
+    read: true
+    write: true
+    drop: true
+  data:
     type_droppable: true
     type_writeable: true
     type_copyable: false
     is_live: true
     path_uninitialized: false
-    permissions:
-      read: true
-      write: true
-      drop: true
 - location:
     line: 7
     column: 2
@@ -44,15 +44,15 @@ description: main@closure_0.test
     write: true
     drop: false
   actual:
+    read: true
+    write: true
+    drop: true
+  data:
     type_droppable: true
     type_writeable: true
     type_copyable: false
     is_live: true
     path_uninitialized: false
-    permissions:
-      read: true
-      write: true
-      drop: true
 - location:
     line: 8
     column: 2
@@ -61,15 +61,15 @@ description: main@closure_0.test
     write: true
     drop: false
   actual:
+    read: true
+    write: true
+    drop: true
+  data:
     type_droppable: true
     type_writeable: true
     type_copyable: false
     is_live: true
     path_uninitialized: false
-    permissions:
-      read: true
-      write: true
-      drop: true
 - location:
     line: 9
     column: 17
@@ -78,13 +78,12 @@ description: main@closure_0.test
     write: false
     drop: false
   actual:
+    read: true
+    write: true
+    drop: true
+  data:
     type_droppable: true
     type_writeable: true
     type_copyable: false
     is_live: true
     path_uninitialized: false
-    permissions:
-      read: true
-      write: true
-      drop: true
-
diff --git a/crates/aquascope/tests/snapshots/boundaries__main@if_0.test.snap b/crates/aquascope/tests/snapshots/boundaries__main@if_0.test.snap
index 69ee50ca8..a5c5883d4 100644
--- a/crates/aquascope/tests/snapshots/boundaries__main@if_0.test.snap
+++ b/crates/aquascope/tests/snapshots/boundaries__main@if_0.test.snap
@@ -10,15 +10,15 @@ description: main@if_0.test
     write: true
     drop: false
   actual:
+    read: true
+    write: true
+    drop: true
+  data:
     type_droppable: true
     type_writeable: true
     type_copyable: false
     is_live: true
     path_uninitialized: false
-    permissions:
-      read: true
-      write: true
-      drop: true
 - location:
     line: 7
     column: 9
@@ -27,15 +27,15 @@ description: main@if_0.test
     write: true
     drop: false
   actual:
+    read: true
+    write: true
+    drop: true
+  data:
     type_droppable: true
     type_writeable: true
     type_copyable: false
     is_live: true
     path_uninitialized: false
-    permissions:
-      read: true
-      write: true
-      drop: true
 - location:
     line: 10
     column: 3
@@ -44,15 +44,15 @@ description: main@if_0.test
     write: true
     drop: false
   actual:
+    read: true
+    write: true
+    drop: false
+  data:
     type_droppable: false
     type_writeable: true
     type_copyable: false
     is_live: true
     path_uninitialized: false
-    permissions:
-      read: true
-      write: true
-      drop: false
 - location:
     line: 12
     column: 4
@@ -61,15 +61,15 @@ description: main@if_0.test
     write: true
     drop: false
   actual:
+    read: true
+    write: true
+    drop: true
+  data:
     type_droppable: true
     type_writeable: true
     type_copyable: false
     is_live: true
     path_uninitialized: false
-    permissions:
-      read: true
-      write: true
-      drop: true
 - location:
     line: 13
     column: 4
@@ -78,13 +78,12 @@ description: main@if_0.test
     write: true
     drop: false
   actual:
+    read: true
+    write: true
+    drop: true
+  data:
     type_droppable: true
     type_writeable: true
     type_copyable: false
     is_live: true
     path_uninitialized: false
-    permissions:
-      read: true
-      write: true
-      drop: true
-
diff --git a/crates/aquascope/tests/snapshots/boundaries__main@if_1.test.snap b/crates/aquascope/tests/snapshots/boundaries__main@if_1.test.snap
index 8bedef98d..d9c043908 100644
--- a/crates/aquascope/tests/snapshots/boundaries__main@if_1.test.snap
+++ b/crates/aquascope/tests/snapshots/boundaries__main@if_1.test.snap
@@ -10,15 +10,15 @@ description: main@if_1.test
     write: true
     drop: false
   actual:
+    read: true
+    write: true
+    drop: true
+  data:
     type_droppable: true
     type_writeable: true
     type_copyable: false
     is_live: true
     path_uninitialized: false
-    permissions:
-      read: true
-      write: true
-      drop: true
 - location:
     line: 9
     column: 13
@@ -27,15 +27,15 @@ description: main@if_1.test
     write: true
     drop: false
   actual:
+    read: true
+    write: true
+    drop: true
+  data:
     type_droppable: true
     type_writeable: true
     type_copyable: false
     is_live: true
     path_uninitialized: false
-    permissions:
-      read: true
-      write: true
-      drop: true
 - location:
     line: 12
     column: 3
@@ -44,15 +44,15 @@ description: main@if_1.test
     write: true
     drop: false
   actual:
+    read: true
+    write: true
+    drop: false
+  data:
     type_droppable: false
     type_writeable: true
     type_copyable: false
     is_live: true
     path_uninitialized: false
-    permissions:
-      read: true
-      write: true
-      drop: false
 - location:
     line: 14
     column: 4
@@ -61,15 +61,15 @@ description: main@if_1.test
     write: true
     drop: false
   actual:
+    read: true
+    write: true
+    drop: true
+  data:
     type_droppable: true
     type_writeable: true
     type_copyable: false
     is_live: true
     path_uninitialized: false
-    permissions:
-      read: true
-      write: true
-      drop: true
 - location:
     line: 15
     column: 4
@@ -78,13 +78,12 @@ description: main@if_1.test
     write: true
     drop: false
   actual:
+    read: true
+    write: true
+    drop: true
+  data:
     type_droppable: true
     type_writeable: true
     type_copyable: false
     is_live: true
     path_uninitialized: false
-    permissions:
-      read: true
-      write: true
-      drop: true
-
diff --git a/crates/aquascope/tests/snapshots/boundaries__main@match_0.test.snap b/crates/aquascope/tests/snapshots/boundaries__main@match_0.test.snap
index 7efa229fa..0cf6715ba 100644
--- a/crates/aquascope/tests/snapshots/boundaries__main@match_0.test.snap
+++ b/crates/aquascope/tests/snapshots/boundaries__main@match_0.test.snap
@@ -10,15 +10,15 @@ description: main@match_0.test
     write: false
     drop: false
   actual:
+    read: true
+    write: false
+    drop: true
+  data:
     type_droppable: true
     type_writeable: false
     type_copyable: false
     is_live: true
     path_uninitialized: false
-    permissions:
-      read: true
-      write: false
-      drop: true
 - location:
     line: 9
     column: 7
@@ -27,13 +27,12 @@ description: main@match_0.test
     write: false
     drop: true
   actual:
+    read: true
+    write: false
+    drop: true
+  data:
     type_droppable: true
     type_writeable: false
     type_copyable: false
     is_live: true
     path_uninitialized: false
-    permissions:
-      read: true
-      write: false
-      drop: true
-
diff --git a/crates/aquascope/tests/snapshots/boundaries__main@read_on_copy_0.test.snap b/crates/aquascope/tests/snapshots/boundaries__main@read_on_copy_0.test.snap
index 6a2bfb697..19b72119e 100644
--- a/crates/aquascope/tests/snapshots/boundaries__main@read_on_copy_0.test.snap
+++ b/crates/aquascope/tests/snapshots/boundaries__main@read_on_copy_0.test.snap
@@ -10,15 +10,15 @@ description: main@read_on_copy_0.test
     write: false
     drop: false
   actual:
+    read: true
+    write: false
+    drop: false
+  data:
     type_droppable: false
     type_writeable: false
     type_copyable: true
     is_live: true
     path_uninitialized: false
-    permissions:
-      read: true
-      write: false
-      drop: false
 - location:
     line: 10
     column: 3
@@ -27,15 +27,15 @@ description: main@read_on_copy_0.test
     write: false
     drop: false
   actual:
+    read: true
+    write: false
+    drop: false
+  data:
     type_droppable: false
     type_writeable: false
     type_copyable: true
     is_live: true
     path_uninitialized: false
-    permissions:
-      read: true
-      write: false
-      drop: false
 - location:
     line: 11
     column: 3
@@ -44,15 +44,15 @@ description: main@read_on_copy_0.test
     write: false
     drop: false
   actual:
+    read: true
+    write: false
+    drop: false
+  data:
     type_droppable: false
     type_writeable: false
     type_copyable: true
     is_live: true
     path_uninitialized: false
-    permissions:
-      read: true
-      write: false
-      drop: false
 - location:
     line: 12
     column: 3
@@ -61,13 +61,12 @@ description: main@read_on_copy_0.test
     write: false
     drop: false
   actual:
+    read: true
+    write: false
+    drop: false
+  data:
     type_droppable: false
     type_writeable: false
     type_copyable: true
     is_live: true
     path_uninitialized: false
-    permissions:
-      read: true
-      write: false
-      drop: false
-
diff --git a/crates/aquascope/tests/snapshots/boundaries__main@struct_udpate.test.snap b/crates/aquascope/tests/snapshots/boundaries__main@struct_udpate.test.snap
new file mode 100644
index 000000000..ce22b0a4b
--- /dev/null
+++ b/crates/aquascope/tests/snapshots/boundaries__main@struct_udpate.test.snap
@@ -0,0 +1,89 @@
+---
+source: crates/aquascope/tests/boundaries.rs
+description: main@struct_udpate.test
+---
+- location:
+    line: 7
+    column: 4
+  expected:
+    read: true
+    write: true
+    drop: false
+  actual:
+    read: true
+    write: true
+    drop: true
+  data:
+    type_droppable: true
+    type_writeable: true
+    type_copyable: true
+    is_live: true
+    path_uninitialized: false
+- location:
+    line: 8
+    column: 29
+  expected:
+    read: true
+    write: false
+    drop: true
+  actual:
+    read: true
+    write: true
+    drop: true
+  data:
+    type_droppable: true
+    type_writeable: true
+    type_copyable: false
+    is_live: true
+    path_uninitialized: false
+- location:
+    line: 9
+    column: 4
+  expected:
+    read: true
+    write: true
+    drop: false
+  actual:
+    read: true
+    write: true
+    drop: true
+  data:
+    type_droppable: true
+    type_writeable: true
+    type_copyable: true
+    is_live: true
+    path_uninitialized: false
+- location:
+    line: 10
+    column: 22
+  expected:
+    read: true
+    write: false
+    drop: false
+  actual:
+    read: true
+    write: false
+    drop: true
+  data:
+    type_droppable: true
+    type_writeable: false
+    type_copyable: false
+    is_live: true
+    path_uninitialized: false
+- location:
+    line: 10
+    column: 30
+  expected:
+    read: true
+    write: false
+    drop: false
+  actual:
+    read: true
+    write: false
+    drop: true
+  data:
+    type_droppable: true
+    type_writeable: false
+    type_copyable: true
+    is_live: true
+    path_uninitialized: false
diff --git a/crates/aquascope/tests/snapshots/boundaries__print_first@type-driven-flows.test.snap b/crates/aquascope/tests/snapshots/boundaries__print_first@type-driven-flows.test.snap
index bef31ac4d..6c476eb08 100644
--- a/crates/aquascope/tests/snapshots/boundaries__print_first@type-driven-flows.test.snap
+++ b/crates/aquascope/tests/snapshots/boundaries__print_first@type-driven-flows.test.snap
@@ -10,15 +10,15 @@ description: print_first@type-driven-flows.test
     write: false
     drop: false
   actual:
+    read: true
+    write: false
+    drop: false
+  data:
     type_droppable: false
     type_writeable: false
     type_copyable: false
     is_live: true
     path_uninitialized: false
-    permissions:
-      read: true
-      write: false
-      drop: false
 - location:
     line: 12
     column: 17
@@ -27,13 +27,12 @@ description: print_first@type-driven-flows.test
     write: false
     drop: false
   actual:
+    read: true
+    write: false
+    drop: true
+  data:
     type_droppable: true
     type_writeable: false
     type_copyable: true
     is_live: true
     path_uninitialized: false
-    permissions:
-      read: true
-      write: false
-      drop: true
-
diff --git a/crates/aquascope/tests/snapshots/interpreter__basic.test.snap b/crates/aquascope/tests/snapshots/interpreter__basic.test.snap
index eb10ea432..f82cc30b0 100644
--- a/crates/aquascope/tests/snapshots/interpreter__basic.test.snap
+++ b/crates/aquascope/tests/snapshots/interpreter__basic.test.snap
@@ -14,7 +14,7 @@ steps:
               line: 4
               column: 1
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           location:
             start:
               line: 0
@@ -23,7 +23,7 @@ steps:
               line: 0
               column: 9
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           locals: []
     heap:
       locations: []
@@ -38,7 +38,7 @@ steps:
               line: 4
               column: 1
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           location:
             start:
               line: 1
@@ -47,7 +47,7 @@ steps:
               line: 1
               column: 16
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           locals:
             - name: x
               value:
@@ -67,7 +67,7 @@ steps:
               line: 4
               column: 1
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           location:
             start:
               line: 2
@@ -76,7 +76,7 @@ steps:
               line: 2
               column: 12
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           locals:
             - name: x
               value:
@@ -101,7 +101,7 @@ steps:
               line: 4
               column: 1
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           location:
             start:
               line: 3
@@ -110,7 +110,7 @@ steps:
               line: 3
               column: 9
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           locals:
             - name: x
               value:
@@ -135,7 +135,7 @@ steps:
               line: 4
               column: 1
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           location:
             start:
               line: 4
@@ -144,10 +144,9 @@ steps:
               line: 4
               column: 1
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           locals: []
     heap:
       locations: []
 result:
   type: Success
-
diff --git a/crates/aquascope/tests/snapshots/interpreter__box.test.snap b/crates/aquascope/tests/snapshots/interpreter__box.test.snap
index c43d29ce3..0b91fa31b 100644
--- a/crates/aquascope/tests/snapshots/interpreter__box.test.snap
+++ b/crates/aquascope/tests/snapshots/interpreter__box.test.snap
@@ -14,7 +14,7 @@ steps:
               line: 4
               column: 1
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           location:
             start:
               line: 0
@@ -23,7 +23,7 @@ steps:
               line: 0
               column: 9
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           locals: []
     heap:
       locations: []
@@ -38,7 +38,7 @@ steps:
               line: 4
               column: 1
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           location:
             start:
               line: 1
@@ -47,7 +47,7 @@ steps:
               line: 1
               column: 26
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           locals:
             - name: x
               value:
@@ -98,7 +98,7 @@ steps:
               line: 4
               column: 1
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           location:
             start:
               line: 2
@@ -107,7 +107,7 @@ steps:
               line: 2
               column: 10
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           locals:
             - name: x
               value:
@@ -158,7 +158,7 @@ steps:
               line: 4
               column: 1
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           location:
             start:
               line: 3
@@ -167,7 +167,7 @@ steps:
               line: 3
               column: 12
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           locals:
             - name: x
               value:
@@ -253,7 +253,7 @@ steps:
               line: 4
               column: 1
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           location:
             start:
               line: 4
@@ -262,10 +262,9 @@ steps:
               line: 4
               column: 1
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           locals: []
     heap:
       locations: []
 result:
   type: Success
-
diff --git a/crates/aquascope/tests/snapshots/interpreter__closure.test.snap b/crates/aquascope/tests/snapshots/interpreter__closure.test.snap
index 1f35abd2b..ea423bbf8 100644
--- a/crates/aquascope/tests/snapshots/interpreter__closure.test.snap
+++ b/crates/aquascope/tests/snapshots/interpreter__closure.test.snap
@@ -14,7 +14,7 @@ steps:
               line: 4
               column: 1
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           location:
             start:
               line: 0
@@ -23,7 +23,7 @@ steps:
               line: 0
               column: 9
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           locals: []
     heap:
       locations: []
@@ -38,7 +38,7 @@ steps:
               line: 4
               column: 1
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           location:
             start:
               line: 1
@@ -47,7 +47,7 @@ steps:
               line: 1
               column: 12
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           locals:
             - name: x
               value:
@@ -67,7 +67,7 @@ steps:
               line: 4
               column: 1
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           location:
             start:
               line: 2
@@ -76,7 +76,7 @@ steps:
               line: 2
               column: 15
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           locals:
             - name: x
               value:
@@ -116,7 +116,7 @@ steps:
               line: 4
               column: 1
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           location:
             start:
               line: 3
@@ -125,7 +125,7 @@ steps:
               line: 3
               column: 14
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           locals:
             - name: x
               value:
@@ -165,7 +165,7 @@ steps:
               line: 4
               column: 1
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           location:
             start:
               line: 3
@@ -174,7 +174,7 @@ steps:
               line: 3
               column: 14
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           locals:
             - name: x
               value:
@@ -210,7 +210,7 @@ steps:
               line: 2
               column: 14
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           location:
             start:
               line: 2
@@ -219,7 +219,7 @@ steps:
               line: 2
               column: 12
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           locals: []
     heap:
       locations: []
@@ -234,7 +234,7 @@ steps:
               line: 4
               column: 1
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           location:
             start:
               line: 3
@@ -243,7 +243,7 @@ steps:
               line: 3
               column: 14
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           locals:
             - name: x
               value:
@@ -279,7 +279,7 @@ steps:
               line: 2
               column: 14
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           location:
             start:
               line: 2
@@ -288,7 +288,7 @@ steps:
               line: 2
               column: 14
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           locals:
             - name: (return)
               value:
@@ -308,7 +308,7 @@ steps:
               line: 4
               column: 1
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           location:
             start:
               line: 3
@@ -317,7 +317,7 @@ steps:
               line: 3
               column: 14
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           locals:
             - name: x
               value:
@@ -362,7 +362,7 @@ steps:
               line: 4
               column: 1
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           location:
             start:
               line: 4
@@ -371,10 +371,9 @@ steps:
               line: 4
               column: 1
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           locals: []
     heap:
       locations: []
 result:
   type: Success
-
diff --git a/crates/aquascope/tests/snapshots/interpreter__error.test.snap b/crates/aquascope/tests/snapshots/interpreter__error.test.snap
index c9d88b8eb..923d7a110 100644
--- a/crates/aquascope/tests/snapshots/interpreter__error.test.snap
+++ b/crates/aquascope/tests/snapshots/interpreter__error.test.snap
@@ -14,7 +14,7 @@ steps:
               line: 5
               column: 1
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           location:
             start:
               line: 0
@@ -23,7 +23,7 @@ steps:
               line: 0
               column: 9
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           locals: []
     heap:
       locations: []
@@ -38,7 +38,7 @@ steps:
               line: 5
               column: 1
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           location:
             start:
               line: 1
@@ -47,7 +47,7 @@ steps:
               line: 1
               column: 28
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           locals:
             - name: v
               value:
@@ -62,35 +62,49 @@ steps:
                           name: RawVec
                           variant: ~
                           fields:
-                            - - ptr
+                            - - inner
                               - type: Adt
                                 value:
-                                  name: Unique
+                                  name: RawVecInner
                                   variant: ~
                                   fields:
-                                    - - pointer
+                                    - - ptr
                                       - type: Adt
                                         value:
-                                          name: NonNull
+                                          name: Unique
                                           variant: ~
                                           fields:
                                             - - pointer
-                                              - type: Pointer
+                                              - type: Adt
                                                 value:
-                                                  path:
-                                                    segment:
-                                                      type: Heap
-                                                      value:
-                                                        index: 0
-                                                    parts:
-                                                      - type: Index
-                                                        value: 0
-                                                  range: ~
+                                                  name: NonNull
+                                                  variant: ~
+                                                  fields:
+                                                    - - pointer
+                                                      - type: Pointer
+                                                        value:
+                                                          path:
+                                                            segment:
+                                                              type: Heap
+                                                              value:
+                                                                index: 0
+                                                            parts:
+                                                              - type: Index
+                                                                value: 0
+                                                          range: ~
+                                                  alloc_kind: ~
+                                          alloc_kind: ~
+                                    - - cap
+                                      - type: Adt
+                                        value:
+                                          name: Cap
+                                          variant: ~
+                                          fields:
+                                            - - "0"
+                                              - type: Uint
+                                                value: 3
                                           alloc_kind: ~
                                   alloc_kind: ~
-                            - - cap
-                              - type: Uint
-                                value: 3
                           alloc_kind: ~
                     - - len
                       - type: Uint
@@ -123,7 +137,7 @@ steps:
               line: 5
               column: 1
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           location:
             start:
               line: 2
@@ -132,7 +146,7 @@ steps:
               line: 2
               column: 16
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           locals:
             - name: v
               value:
@@ -147,35 +161,49 @@ steps:
                           name: RawVec
                           variant: ~
                           fields:
-                            - - ptr
+                            - - inner
                               - type: Adt
                                 value:
-                                  name: Unique
+                                  name: RawVecInner
                                   variant: ~
                                   fields:
-                                    - - pointer
+                                    - - ptr
                                       - type: Adt
                                         value:
-                                          name: NonNull
+                                          name: Unique
                                           variant: ~
                                           fields:
                                             - - pointer
-                                              - type: Pointer
+                                              - type: Adt
                                                 value:
-                                                  path:
-                                                    segment:
-                                                      type: Heap
-                                                      value:
-                                                        index: 0
-                                                    parts:
-                                                      - type: Index
-                                                        value: 0
-                                                  range: ~
+                                                  name: NonNull
+                                                  variant: ~
+                                                  fields:
+                                                    - - pointer
+                                                      - type: Pointer
+                                                        value:
+                                                          path:
+                                                            segment:
+                                                              type: Heap
+                                                              value:
+                                                                index: 0
+                                                            parts:
+                                                              - type: Index
+                                                                value: 0
+                                                          range: ~
+                                                  alloc_kind: ~
+                                          alloc_kind: ~
+                                    - - cap
+                                      - type: Adt
+                                        value:
+                                          name: Cap
+                                          variant: ~
+                                          fields:
+                                            - - "0"
+                                              - type: Uint
+                                                value: 3
                                           alloc_kind: ~
                                   alloc_kind: ~
-                            - - cap
-                              - type: Uint
-                                value: 3
                           alloc_kind: ~
                     - - len
                       - type: Uint
@@ -222,7 +250,7 @@ steps:
               line: 5
               column: 1
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           location:
             start:
               line: 3
@@ -231,7 +259,7 @@ steps:
               line: 3
               column: 12
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           locals:
             - name: v
               value:
@@ -246,35 +274,49 @@ steps:
                           name: RawVec
                           variant: ~
                           fields:
-                            - - ptr
+                            - - inner
                               - type: Adt
                                 value:
-                                  name: Unique
+                                  name: RawVecInner
                                   variant: ~
                                   fields:
-                                    - - pointer
+                                    - - ptr
                                       - type: Adt
                                         value:
-                                          name: NonNull
+                                          name: Unique
                                           variant: ~
                                           fields:
                                             - - pointer
-                                              - type: Pointer
+                                              - type: Adt
                                                 value:
-                                                  path:
-                                                    segment:
-                                                      type: Heap
-                                                      value:
-                                                        index: 0
-                                                    parts:
-                                                      - type: Index
-                                                        value: 0
-                                                  range: ~
+                                                  name: NonNull
+                                                  variant: ~
+                                                  fields:
+                                                    - - pointer
+                                                      - type: Pointer
+                                                        value:
+                                                          path:
+                                                            segment:
+                                                              type: Heap
+                                                              value:
+                                                                index: 0
+                                                            parts:
+                                                              - type: Index
+                                                                value: 0
+                                                          range: ~
+                                                  alloc_kind: ~
+                                          alloc_kind: ~
+                                    - - cap
+                                      - type: Adt
+                                        value:
+                                          name: Cap
+                                          variant: ~
+                                          fields:
+                                            - - "0"
+                                              - type: Uint
+                                                value: 6
                                           alloc_kind: ~
                                   alloc_kind: ~
-                            - - cap
-                              - type: Uint
-                                value: 6
                           alloc_kind: ~
                     - - len
                       - type: Uint
@@ -315,7 +357,7 @@ steps:
               line: 5
               column: 1
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           location:
             start:
               line: 4
@@ -324,7 +366,7 @@ steps:
               line: 4
               column: 13
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           locals:
             - name: v
               value:
@@ -339,35 +381,49 @@ steps:
                           name: RawVec
                           variant: ~
                           fields:
-                            - - ptr
+                            - - inner
                               - type: Adt
                                 value:
-                                  name: Unique
+                                  name: RawVecInner
                                   variant: ~
                                   fields:
-                                    - - pointer
+                                    - - ptr
                                       - type: Adt
                                         value:
-                                          name: NonNull
+                                          name: Unique
                                           variant: ~
                                           fields:
                                             - - pointer
-                                              - type: Pointer
+                                              - type: Adt
                                                 value:
-                                                  path:
-                                                    segment:
-                                                      type: Heap
-                                                      value:
-                                                        index: 0
-                                                    parts:
-                                                      - type: Index
-                                                        value: 0
-                                                  range: ~
+                                                  name: NonNull
+                                                  variant: ~
+                                                  fields:
+                                                    - - pointer
+                                                      - type: Pointer
+                                                        value:
+                                                          path:
+                                                            segment:
+                                                              type: Heap
+                                                              value:
+                                                                index: 0
+                                                            parts:
+                                                              - type: Index
+                                                                value: 0
+                                                          range: ~
+                                                  alloc_kind: ~
+                                          alloc_kind: ~
+                                    - - cap
+                                      - type: Adt
+                                        value:
+                                          name: Cap
+                                          variant: ~
+                                          fields:
+                                            - - "0"
+                                              - type: Uint
+                                                value: 6
                                           alloc_kind: ~
                                   alloc_kind: ~
-                            - - cap
-                              - type: Uint
-                                value: 6
                           alloc_kind: ~
                     - - len
                       - type: Uint
@@ -403,4 +459,3 @@ result:
     type: PointerUseAfterFree
     value:
       alloc_id: 0
-
diff --git a/crates/aquascope/tests/snapshots/interpreter__nested-ref.test.snap b/crates/aquascope/tests/snapshots/interpreter__nested-ref.test.snap
index d75985c90..979b80fe8 100644
--- a/crates/aquascope/tests/snapshots/interpreter__nested-ref.test.snap
+++ b/crates/aquascope/tests/snapshots/interpreter__nested-ref.test.snap
@@ -14,7 +14,7 @@ steps:
               line: 3
               column: 1
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           location:
             start:
               line: 0
@@ -23,7 +23,7 @@ steps:
               line: 0
               column: 9
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           locals: []
     heap:
       locations: []
@@ -38,7 +38,7 @@ steps:
               line: 3
               column: 1
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           location:
             start:
               line: 1
@@ -47,7 +47,7 @@ steps:
               line: 1
               column: 27
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           locals:
             - name: x
               value:
@@ -81,7 +81,7 @@ steps:
               line: 3
               column: 1
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           location:
             start:
               line: 2
@@ -90,7 +90,7 @@ steps:
               line: 2
               column: 18
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           locals:
             - name: x
               value:
@@ -141,7 +141,7 @@ steps:
               line: 3
               column: 1
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           location:
             start:
               line: 3
@@ -150,10 +150,9 @@ steps:
               line: 3
               column: 1
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           locals: []
     heap:
       locations: []
 result:
   type: Success
-
diff --git a/crates/aquascope/tests/snapshots/interpreter__stackref.test.snap b/crates/aquascope/tests/snapshots/interpreter__stackref.test.snap
index a4e395eba..3f5073d2e 100644
--- a/crates/aquascope/tests/snapshots/interpreter__stackref.test.snap
+++ b/crates/aquascope/tests/snapshots/interpreter__stackref.test.snap
@@ -14,7 +14,7 @@ steps:
               line: 4
               column: 1
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           location:
             start:
               line: 0
@@ -23,7 +23,7 @@ steps:
               line: 0
               column: 9
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           locals: []
     heap:
       locations: []
@@ -38,7 +38,7 @@ steps:
               line: 4
               column: 1
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           location:
             start:
               line: 1
@@ -47,7 +47,7 @@ steps:
               line: 1
               column: 16
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           locals:
             - name: x
               value:
@@ -67,7 +67,7 @@ steps:
               line: 4
               column: 1
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           location:
             start:
               line: 2
@@ -76,7 +76,7 @@ steps:
               line: 2
               column: 17
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           locals:
             - name: x
               value:
@@ -109,7 +109,7 @@ steps:
               line: 4
               column: 1
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           location:
             start:
               line: 3
@@ -118,7 +118,7 @@ steps:
               line: 3
               column: 10
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           locals:
             - name: x
               value:
@@ -151,7 +151,7 @@ steps:
               line: 4
               column: 1
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           location:
             start:
               line: 4
@@ -160,10 +160,9 @@ steps:
               line: 4
               column: 1
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           locals: []
     heap:
       locations: []
 result:
   type: Success
-
diff --git a/crates/aquascope/tests/snapshots/interpreter__tuple.test.snap b/crates/aquascope/tests/snapshots/interpreter__tuple.test.snap
index 34a253e2c..d66011a34 100644
--- a/crates/aquascope/tests/snapshots/interpreter__tuple.test.snap
+++ b/crates/aquascope/tests/snapshots/interpreter__tuple.test.snap
@@ -14,7 +14,7 @@ steps:
               line: 3
               column: 1
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           location:
             start:
               line: 0
@@ -23,7 +23,7 @@ steps:
               line: 0
               column: 9
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           locals: []
     heap:
       locations: []
@@ -38,7 +38,7 @@ steps:
               line: 3
               column: 1
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           location:
             start:
               line: 1
@@ -47,7 +47,7 @@ steps:
               line: 1
               column: 41
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           locals:
             - name: x
               value:
@@ -72,35 +72,49 @@ steps:
                                       name: RawVec
                                       variant: ~
                                       fields:
-                                        - - ptr
+                                        - - inner
                                           - type: Adt
                                             value:
-                                              name: Unique
+                                              name: RawVecInner
                                               variant: ~
                                               fields:
-                                                - - pointer
+                                                - - ptr
                                                   - type: Adt
                                                     value:
-                                                      name: NonNull
+                                                      name: Unique
                                                       variant: ~
                                                       fields:
                                                         - - pointer
-                                                          - type: Pointer
+                                                          - type: Adt
                                                             value:
-                                                              path:
-                                                                segment:
-                                                                  type: Heap
-                                                                  value:
-                                                                    index: 0
-                                                                parts:
-                                                                  - type: Index
-                                                                    value: 0
-                                                              range: ~
+                                                              name: NonNull
+                                                              variant: ~
+                                                              fields:
+                                                                - - pointer
+                                                                  - type: Pointer
+                                                                    value:
+                                                                      path:
+                                                                        segment:
+                                                                          type: Heap
+                                                                          value:
+                                                                            index: 0
+                                                                        parts:
+                                                                          - type: Index
+                                                                            value: 0
+                                                                      range: ~
+                                                              alloc_kind: ~
+                                                      alloc_kind: ~
+                                                - - cap
+                                                  - type: Adt
+                                                    value:
+                                                      name: Cap
+                                                      variant: ~
+                                                      fields:
+                                                        - - "0"
+                                                          - type: Uint
+                                                            value: 5
                                                       alloc_kind: ~
                                               alloc_kind: ~
-                                        - - cap
-                                          - type: Uint
-                                            value: 5
                                       alloc_kind: ~
                                 - - len
                                   - type: Uint
@@ -138,7 +152,7 @@ steps:
               line: 3
               column: 1
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           location:
             start:
               line: 2
@@ -147,7 +161,7 @@ steps:
               line: 2
               column: 11
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           locals:
             - name: x
               value:
@@ -172,35 +186,49 @@ steps:
                                       name: RawVec
                                       variant: ~
                                       fields:
-                                        - - ptr
+                                        - - inner
                                           - type: Adt
                                             value:
-                                              name: Unique
+                                              name: RawVecInner
                                               variant: ~
                                               fields:
-                                                - - pointer
+                                                - - ptr
                                                   - type: Adt
                                                     value:
-                                                      name: NonNull
+                                                      name: Unique
                                                       variant: ~
                                                       fields:
                                                         - - pointer
-                                                          - type: Pointer
+                                                          - type: Adt
                                                             value:
-                                                              path:
-                                                                segment:
-                                                                  type: Heap
-                                                                  value:
-                                                                    index: 0
-                                                                parts:
-                                                                  - type: Index
-                                                                    value: 0
-                                                              range: ~
+                                                              name: NonNull
+                                                              variant: ~
+                                                              fields:
+                                                                - - pointer
+                                                                  - type: Pointer
+                                                                    value:
+                                                                      path:
+                                                                        segment:
+                                                                          type: Heap
+                                                                          value:
+                                                                            index: 0
+                                                                        parts:
+                                                                          - type: Index
+                                                                            value: 0
+                                                                      range: ~
+                                                              alloc_kind: ~
+                                                      alloc_kind: ~
+                                                - - cap
+                                                  - type: Adt
+                                                    value:
+                                                      name: Cap
+                                                      variant: ~
+                                                      fields:
+                                                        - - "0"
+                                                          - type: Uint
+                                                            value: 5
                                                       alloc_kind: ~
                                               alloc_kind: ~
-                                        - - cap
-                                          - type: Uint
-                                            value: 5
                                       alloc_kind: ~
                                 - - len
                                   - type: Uint
@@ -238,7 +266,7 @@ steps:
               line: 3
               column: 1
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           location:
             start:
               line: 3
@@ -247,10 +275,9 @@ steps:
               line: 3
               column: 1
             filename:
-              private: 0
+              private_use_as_methods_instead: 0
           locals: []
     heap:
       locations: []
 result:
   type: Success
-
diff --git a/crates/aquascope/tests/stepper.rs b/crates/aquascope/tests/stepper.rs
index 3758e3ef2..45e4c671f 100644
--- a/crates/aquascope/tests/stepper.rs
+++ b/crates/aquascope/tests/stepper.rs
@@ -1,3 +1,5 @@
+#![feature(rustc_private)]
+
 use aquascope::test_utils;
 
 #[test_log::test]