diff --git a/.claude/commands b/.claude/commands
index 9b64bee7..d004f83c 160000
--- a/.claude/commands
+++ b/.claude/commands
@@ -1 +1 @@
-Subproject commit 9b64bee71225a25bd627c3a4e3bc51942df979e6
+Subproject commit d004f83c8aabb064b058680385f7e7810437a500
diff --git a/internal b/internal
index 76f4fb84..03329929 160000
--- a/internal
+++ b/internal
@@ -1 +1 @@
-Subproject commit 76f4fb8492ed553b3e5d8b6e8b0d27c628bbfb52
+Subproject commit 03329929f002effdfb5e191f7774b3481fcd23e5
diff --git a/src/Backend/AutopilotMonitor.Functions.Tests/Shared/ErrorCodeCatalogTests.cs b/src/Backend/AutopilotMonitor.Functions.Tests/Shared/ErrorCodeCatalogTests.cs
index a09e04ee..383abfd5 100644
--- a/src/Backend/AutopilotMonitor.Functions.Tests/Shared/ErrorCodeCatalogTests.cs
+++ b/src/Backend/AutopilotMonitor.Functions.Tests/Shared/ErrorCodeCatalogTests.cs
@@ -9,7 +9,7 @@ using Xunit;
namespace AutopilotMonitor.Functions.Tests.Shared;
///
-/// Pins the schemaVersion-2 catalog contract (generated by scripts/error-codes/generate.mjs):
+/// Pins the schemaVersion-2 catalog contract (generated by tools/error-codes/generate.mjs):
/// key/source/category vocabulary, the HRESULT_FROM_WIN32 derivation, the symbol and
/// enforcement-state indexes, and the handful of entries product code and rules rely on.
///
diff --git a/src/Shared/AutopilotMonitor.Shared/Models/ErrorCodeEntry.cs b/src/Shared/AutopilotMonitor.Shared/Models/ErrorCodeEntry.cs
index 13834f4d..d59a243b 100644
--- a/src/Shared/AutopilotMonitor.Shared/Models/ErrorCodeEntry.cs
+++ b/src/Shared/AutopilotMonitor.Shared/Models/ErrorCodeEntry.cs
@@ -20,7 +20,7 @@ namespace AutopilotMonitor.Shared.Models
///
/// One Windows / MSI / Intune error-code catalog entry. Mirrors the structure of
- /// Resources/error-codes.json (generated by scripts/error-codes/generate.mjs)
+ /// Resources/error-codes.json (generated by tools/error-codes/generate.mjs)
/// and the TypeScript ErrorCodeEntry in the web app.
///
public sealed class ErrorCodeEntry
diff --git a/src/Shared/AutopilotMonitor.Shared/Resources/error-codes.json b/src/Shared/AutopilotMonitor.Shared/Resources/error-codes.json
index f86c5672..00415260 100644
--- a/src/Shared/AutopilotMonitor.Shared/Resources/error-codes.json
+++ b/src/Shared/AutopilotMonitor.Shared/Resources/error-codes.json
@@ -1,6 +1,6 @@
{
"schemaVersion": 2,
- "description": "Single-source catalog of Windows / MSI / Intune error codes, generated by scripts/error-codes/generate.mjs from primary sources — never edit by hand. Consumed by the backend (ErrorCodeCatalog.cs, ErrorCodeEnricher.cs), the web app (utils/errorCodeMap.ts via the sync-error-codes prebuild step) and the MCP server (lookup_error_code). Keys are lowercase 8-digit hex ('0x80070005') or decimal MSI exit codes ('1603'; only 0, 1601-1654, 3010 — other decimal exit codes are installer-defined). Win32 codes live only as 0x8007xxxx entries; HRESULT_FROM_WIN32 values in the MSI range resolve to the decimal entry at lookup time. confidence: high = MS Learn or the IME build named in source; medium = paraphrase of an enum member name or of an analysis rule; low = carried over from the v1 catalog without a primary source. category is one of: msi, win32, com, appx, windows-update, cbs, intune-win32, intune-mobile, mdm-enrollment, autopilot, entra-join, delivery-optimization. imeRetriesDuringEsp marks the MSI return codes the IME retries automatically during the Autopilot ESP. enforcementStates maps the IME app enforcement state numbers to their names.",
+ "description": "Single-source catalog of Windows / MSI / Intune error codes, generated by tools/error-codes/generate.mjs from primary sources — never edit by hand. Consumed by the backend (ErrorCodeCatalog.cs, ErrorCodeEnricher.cs), the web app (utils/errorCodeMap.ts via the sync-error-codes prebuild step) and the MCP server (lookup_error_code). Keys are lowercase 8-digit hex ('0x80070005') or decimal MSI exit codes ('1603'; only 0, 1601-1654, 3010 — other decimal exit codes are installer-defined). Win32 codes live only as 0x8007xxxx entries; HRESULT_FROM_WIN32 values in the MSI range resolve to the decimal entry at lookup time. confidence: high = MS Learn or the IME build named in source; medium = paraphrase of an enum member name or of an analysis rule; low = carried over from the v1 catalog without a primary source. category is one of: msi, win32, com, appx, windows-update, cbs, intune-win32, intune-mobile, mdm-enrollment, autopilot, entra-join, delivery-optimization. imeRetriesDuringEsp marks the MSI return codes the IME retries automatically during the Autopilot ESP. enforcementStates maps the IME app enforcement state numbers to their names.",
"entries": {
"0": {"description":"The action completed successfully","confidence":"high","source":"msdoc:https://learn.microsoft.com/en-us/windows/win32/msi/error-codes","category":"msi","symbol":"ERROR_SUCCESS"},
"1601": {"description":"The Windows Installer service couldn't be accessed. Contact your support personnel to verify that the Windows Installer service is properly registered","confidence":"high","source":"msdoc:https://learn.microsoft.com/en-us/windows/win32/msi/error-codes","category":"msi","symbol":"ERROR_INSTALL_SERVICE_FAILURE"},
diff --git a/src/Shared/AutopilotMonitor.Shared/Services/ErrorCodeCatalog.cs b/src/Shared/AutopilotMonitor.Shared/Services/ErrorCodeCatalog.cs
index d70dd0b4..0e8bf0c6 100644
--- a/src/Shared/AutopilotMonitor.Shared/Services/ErrorCodeCatalog.cs
+++ b/src/Shared/AutopilotMonitor.Shared/Services/ErrorCodeCatalog.cs
@@ -13,7 +13,7 @@ namespace AutopilotMonitor.Shared.Services
///
/// Single-source-of-truth lookup for Windows / MSI / Intune error codes. Loaded once
/// from the embedded Resources/error-codes.json resource (schemaVersion 2,
- /// generated by scripts/error-codes/generate.mjs) and exposed via dictionaries
+ /// generated by tools/error-codes/generate.mjs) and exposed via dictionaries
/// keyed by normalised code string (lowercase hex, e.g. 0x80070005, or decimal MSI
/// exit code, e.g. 1603), by symbol and by enforcement state.
///
diff --git a/src/Web/autopilot-monitor-web/scripts/sync-error-codes.js b/src/Web/autopilot-monitor-web/scripts/sync-error-codes.js
index 37833511..0eebdb9c 100644
--- a/src/Web/autopilot-monitor-web/scripts/sync-error-codes.js
+++ b/src/Web/autopilot-monitor-web/scripts/sync-error-codes.js
@@ -3,7 +3,7 @@
*
* The authoritative copy lives at:
* src/Shared/AutopilotMonitor.Shared/Resources/error-codes.json
- * (generated by scripts/error-codes/generate.mjs at the repo root; never edited by hand).
+ * (generated by tools/error-codes/generate.mjs at the repo root; never edited by hand).
*
* The backend (ErrorCodeCatalog.cs) embeds that file; the web app (utils/errorCodeMap.ts)
* imports the copy this script writes to utils/error-codes.json. The copy is validated,
diff --git a/src/Web/autopilot-monitor-web/utils/errorCodeMap.ts b/src/Web/autopilot-monitor-web/utils/errorCodeMap.ts
index 7e80322d..cc566641 100644
--- a/src/Web/autopilot-monitor-web/utils/errorCodeMap.ts
+++ b/src/Web/autopilot-monitor-web/utils/errorCodeMap.ts
@@ -2,7 +2,7 @@
* Wrapper around the shared error-codes catalog (schemaVersion 2).
*
* The catalog lives at `src/Shared/AutopilotMonitor.Shared/Resources/error-codes.json`
- * (generated by `scripts/error-codes/generate.mjs` at the repo root) and is synced into
+ * (generated by `tools/error-codes/generate.mjs` at the repo root) and is synced into
* `utils/error-codes.json` at build time (`scripts/sync-error-codes.js`, wired into the
* `prebuild` npm script). The sync validates the catalog, shortens `source` to its kind and
* drops the enforcement-state map; backend, MCP and web resolve from the same entries.
diff --git a/scripts/error-codes/README.md b/tools/error-codes/README.md
similarity index 98%
rename from scripts/error-codes/README.md
rename to tools/error-codes/README.md
index dedbcbf7..c125e98a 100644
--- a/scripts/error-codes/README.md
+++ b/tools/error-codes/README.md
@@ -7,7 +7,7 @@ hand: a wrong or missing entry is fixed in the generator (a source, a pin, a fam
regenerated, so the next regeneration cannot lose the fix.
```
-IME_ENUMS_JSON= node scripts/error-codes/generate.mjs [--cache-dir DIR] [--check]
+IME_ENUMS_JSON= node tools/error-codes/generate.mjs [--cache-dir DIR] [--check]
```
- `IME_ENUMS_JSON` — enum extract of one Intune Management Extension build (`imeVersion`,
diff --git a/scripts/error-codes/generate.mjs b/tools/error-codes/generate.mjs
similarity index 99%
rename from scripts/error-codes/generate.mjs
rename to tools/error-codes/generate.mjs
index 3df826fa..ad704f69 100644
--- a/scripts/error-codes/generate.mjs
+++ b/tools/error-codes/generate.mjs
@@ -6,7 +6,7 @@
* sources and writes the web copy through the web sync script. Every entry carries the
* source it was taken from; nothing is typed in from memory.
*
- * node scripts/error-codes/generate.mjs [--cache-dir DIR] [--check]
+ * node tools/error-codes/generate.mjs [--cache-dir DIR] [--check]
*
* IME_ENUMS_JSON required — path to the enum extract of one Intune Management Extension
* build (customErrorCodes, enforcementStates, msiRetriableErrorCodes,
@@ -492,7 +492,7 @@ async function main() {
const header = {
schemaVersion: 2,
description:
- "Single-source catalog of Windows / MSI / Intune error codes, generated by scripts/error-codes/generate.mjs from primary sources — " +
+ "Single-source catalog of Windows / MSI / Intune error codes, generated by tools/error-codes/generate.mjs from primary sources — " +
"never edit by hand. Consumed by the backend (ErrorCodeCatalog.cs, ErrorCodeEnricher.cs), the web app (utils/errorCodeMap.ts via the " +
"sync-error-codes prebuild step) and the MCP server (lookup_error_code). Keys are lowercase 8-digit hex ('0x80070005') or decimal MSI exit " +
"codes ('1603'; only 0, 1601-1654, 3010 — other decimal exit codes are installer-defined). Win32 codes live only as 0x8007xxxx entries; " +