{"record":{"id":"6df8ad946346e872","repo":"affaan-m/ECC","slug":"no-trusted-boundary-policy-is-configured-for-memor","errorCode":null,"errorMessage":"No trusted boundary policy is configured for memory scope \"${scope}\".","messagePattern":"No trusted boundary policy is configured for memory scope \"(.+?)\"\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/lib/memory-vault.js","lineNumber":107,"sourceCode":"    }),\n    enumerable: false,\n    configurable: false,\n    writable: false,\n  });\n  return Object.freeze(roots);\n}\n\nfunction assertMemoryRootSafe(roots, scope) {\n  if (!roots || typeof roots !== 'object' || Array.isArray(roots)) {\n    throw new Error('Memory roots must include a trusted boundary policy.');\n  }\n  const root = roots[scope];\n  if (typeof root !== 'string' || root.length === 0) {\n    throw new Error(`No memory root is configured for scope \"${scope}\".`);\n  }\n  const boundary = roots[VAULT_ROOT_BOUNDARIES]?.[scope];\n  if (typeof boundary !== 'string' || boundary.length === 0) {\n    throw new Error(`No trusted boundary policy is configured for memory scope \"${scope}\".`);\n  }\n  assertWithinTrustedRoot(root, boundary, 'access memory through a symlink');\n  if (fs.existsSync(root) && fs.lstatSync(root).isSymbolicLink()) {\n    throw new Error(`Refusing to access memory through symlink root: ${root}`);\n  }\n  return root;\n}\n\nfunction assertMemoryDirectorySafe(directory, root) {\n  assertWithinTrustedRoot(directory, root, 'access memory directory');\n  if (fs.existsSync(directory) && fs.lstatSync(directory).isSymbolicLink()) {\n    throw new Error(`Refusing to access memory through symlink directory: ${directory}`);\n  }\n  return directory;\n}\n\nfunction sameFileIdentity(left, right) {\n  // The inode is the primary identity signal and must always match.","sourceCodeStart":89,"sourceCodeEnd":125,"githubUrl":"https://github.com/affaan-m/ECC/blob/01e15490f04e29cfefe3896951f43db46994d8ee/scripts/lib/memory-vault.js#L89-L125","documentation":"Thrown by assertMemoryRootSafe() when the hidden Symbol-keyed boundary map (roots[VAULT_ROOT_BOUNDARIES]) does not contain a non-empty string for the requested scope. The boundary is the trusted ancestor directory that the root path must stay inside (defense against symlink escapes). resolveVaultRoots() installs this Symbol property non-enumerably; a hand-built or stripped roots object will not have it.","triggerScenarios":"A test or wrapper that built roots = { project: '/a', team: '/b', user: '/c' } literally without the Symbol boundary map. JSON.parse(JSON.stringify(roots)) which drops the Symbol property. Object.assign({}, roots) which copies only enumerable keys. Spread {...roots} which also omits non-enumerable Symbol keys.","commonSituations":"Test fixture that hand-constructed a roots object. Wrapper that tried to 'clone and modify' roots via spread. Debug logging that serialized and re-parsed roots. Custom resolver that returned a plain object without calling the internal defineProperty for the boundary Symbol.","solutions":["Always use resolveVaultRoots() to produce roots — it installs the Symbol boundary map correctly.","Never clone roots via spread, Object.assign, or JSON round-trip; pass the original frozen object.","If you must override a path, call resolveVaultRoots({ ECC_MEMORY_PROJECT_ROOT, ECC_MEMORY_USER_ROOT }) again.","Treat the boundary map as load-bearing security state — do not strip non-enumerable keys."],"exampleFix":"// before — drops the Symbol boundary map\nconst roots = { ...resolveVaultRoots(), project: '/override' };\nsaveMemory(input, { roots });\n\n// after — re-resolve with env override so the boundary map survives\nconst roots = resolveVaultRoots({ ECC_MEMORY_PROJECT_ROOT: '/override' });\nsaveMemory(input, { roots });","handlingStrategy":"validation","validationCode":"// roots must come from resolveVaultRoots(); never spread or JSON-round-trip\nif (!options.roots) {\n  options.roots = resolveVaultRoots({\n    ECC_MEMORY_PROJECT_ROOT: process.env.ECC_MEMORY_PROJECT_ROOT,\n    ECC_MEMORY_USER_ROOT: process.env.ECC_MEMORY_USER_ROOT,\n  });\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never clone roots via {...roots}, Object.assign({}, roots), or JSON.parse(JSON.stringify(roots)) — Symbol keys are dropped.","Re-resolve roots with the appropriate env var when you need to override a path.","Treat the boundary map as load-bearing security state; do not strip non-enumerable properties."],"tags":["security","validation","memory-vault","roots","trusted-boundary"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}