{"record":{"id":"adf7689a910fb882","repo":"Hmbown/CodeWhale","slug":"workspace-scope-requires-a-workspace-id","errorCode":null,"errorMessage":"workspace scope requires a workspace id","messagePattern":"workspace scope requires a workspace id","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/native_memory.rs","lineNumber":210,"sourceCode":"            fs::write(&target, content)?;\n            self.reindex_file(&target)?;\n            Ok(true)\n        })\n    }\n\n    /// Append a reviewed note to the selected Markdown source and refresh its\n    /// index. The note is treated as data, never as an instruction.\n    pub fn remember(\n        &self,\n        scope: MemoryScope,\n        workspace_id: Option<&str>,\n        note: &str,\n    ) -> Result<MemoryHit> {\n        let note = normalize_note(note)?;\n        let path = match scope {\n            MemoryScope::Global => self.global_path(),\n            MemoryScope::Workspace => self.workspace_path(\n                workspace_id.ok_or_else(|| anyhow!(\"workspace scope requires a workspace id\"))?,\n            )?,\n        };\n        self.with_write_lock(|| {\n            ensure_memory_file(&path)?;\n            let before = fs::read_to_string(&path).unwrap_or_default();\n            let line_start = before.lines().count().saturating_add(2);\n            let mut file = OpenOptions::new()\n                .create(true)\n                .append(true)\n                .open(&path)\n                .with_context(|| format!(\"open memory source {}\", path.display()))?;\n            if !before.is_empty() && !before.ends_with('\\n') {\n                writeln!(file)?;\n            }\n            writeln!(file, \"\\n- {note}\")?;\n            file.sync_data()?;\n            self.reindex_file(&path)?;\n            let line_end = line_start;","sourceCodeStart":192,"sourceCodeEnd":228,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/8880682c63083a91624de936797efa3ce9e498fd/crates/tui/src/native_memory.rs#L192-L228","documentation":"Native memory's remember() writes a note to a per-scope Markdown file; the Workspace scope needs a workspace id to compute its path, and None is rejected immediately after normalize_note() validated the text. This is a caller-contract violation, not an environmental failure — the note is treated as data, never instructions.","triggerScenarios":"Calling remember(MemoryScope::Workspace, None, note): the remember tool invoked with scope=workspace while the session had no workspace context or the caller dropped the workspace id.","commonSituations":"Sessions started outside any workspace directory; tool wiring forwarding the scope but not the id; scripted calls hardcoding scope=workspace.","solutions":["Pass the session's workspace id whenever scope is Workspace","When no workspace context exists, record with MemoryScope::Global instead","Fix the caller to resolve the workspace id before choosing the scope"],"exampleFix":"// before\nmemory.remember(MemoryScope::Workspace, None, note)?;\n\n// after\nlet scope = match workspace_id {\n    Some(_) => MemoryScope::Workspace,\n    None => MemoryScope::Global,\n};\nmemory.remember(scope, workspace_id, note)?;","handlingStrategy":"validation","validationCode":"```rust\n// Derive the scope from the id you actually have, before calling remember():\nlet scope = match workspace_id {\n    Some(_) => MemoryScope::Workspace,\n    None => MemoryScope::Global,\n};\nmemory.remember(scope, workspace_id, note)?;\n```","typeGuard":"```rust\nfn requires_workspace_id(scope: MemoryScope) -> bool {\n    matches!(scope, MemoryScope::Workspace)\n}\n```","tryCatchPattern":null,"preventionTips":["Resolve the workspace id from the session before accepting a user-selected scope","Default the scope to Global when no workspace is active instead of erroring"],"tags":["memory","validation","workspace"],"backgroundTag":null,"analyzedSha":"8880682c63083a91624de936797efa3ce9e498fd","analyzedAt":"2026-08-16T11:31:27.956Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}