{"record":{"id":"165b4dc82f17a675","repo":"headroomlabs-ai/headroom","slug":"comparator-cache-aligner-not-implemented-phase-0","errorCode":null,"errorMessage":"comparator cache_aligner not implemented (Phase 0)","messagePattern":"comparator cache_aligner not implemented \\(Phase 0\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"crates/headroom-parity/src/lib.rs","lineNumber":173,"sourceCode":"// * `cache_aligner` — needs the volatile-content detector, which lives in\n//   `headroom-proxy` while this crate depends only on `headroom-core`. Either\n//   add the dependency or move the detector down into core.\n// * `ccr` — the fixtures compare `ccr_retrieve` tool-definition injection\n//   (`headroom/ccr/tool_injection.py`), which has no Rust port at all.\n\nmacro_rules! stub_comparator {\n    ($ty:ident, $name:literal) => {\n        pub struct $ty;\n        impl TransformComparator for $ty {\n            fn name(&self) -> &str {\n                $name\n            }\n            fn run(\n                &self,\n                _input: &serde_json::Value,\n                _config: &serde_json::Value,\n            ) -> Result<serde_json::Value> {\n                anyhow::bail!(concat!(\"comparator \", $name, \" not implemented (Phase 0)\"))\n            }\n        }\n    };\n}\n\nstub_comparator!(CacheAlignerComparator, \"cache_aligner\");\nstub_comparator!(CcrComparator, \"ccr\");\n\n/// Real comparator for the `log_compressor` transform.\n///\n/// Two wrinkles beyond the usual adapter shape:\n///\n/// * **bias.** Python's signature is `compress(content, context=\"\", bias=1.0)`\n///   and the recorder captured only `content`, so every fixture was produced at\n///   the default `bias = 1.0`. Rust takes `bias` positionally — pass 1.0.\n/// * **CCR store.** The Python compressor owns its store internally, while Rust\n///   mints a `cache_key` only when one is handed to `compress_with_store`.\n///   Without a store the CCR branch bails out with `\"no store provided\"` and","sourceCodeStart":155,"sourceCodeEnd":191,"githubUrl":"https://github.com/headroomlabs-ai/headroom/blob/322425c43bffde1ed0b64fecf3cf5951565dd82b/crates/headroom-parity/src/lib.rs#L155-L191","documentation":"HTTP 403 from require_same_origin (loopback_guard.py:245): the request carries 'Origin: null'. Browsers send this from sandboxed iframes, file:// pages, or redirect chains; the guard treats it as an untrustworthy origin and rejects CSRF-style attempts on mutating routes. Non-browser clients send no Origin at all and pass.","triggerScenarios":"A dashboard page served from a file:// URL or a sandboxed iframe issues fetch()/XHR with JSON bodies to the local mutating endpoints; a page that redirected through a data: or blob: URL before the request.","commonSituations":"Opening an HTML report or local tool from disk that talks to the proxy; embedding the dashboard in a sandboxed iframe without allow-same-origin; edge redirects that nullify the origin.","solutions":["Serve the page over http(s) from a proper origin (same host) instead of file://","Add allow-same-origin to the embedding iframe's sandbox attribute","For scripted access, use a non-browser client (curl, SDK) which sends no Origin header"],"exampleFix":"<!-- before -->\n<iframe src=\"http://127.0.0.1:8080/settings\" sandbox=\"allow-scripts\"></iframe>\n<!-- after -->\n<iframe src=\"http://127.0.0.1:8080/settings\" sandbox=\"allow-scripts allow-same-origin\"></iframe>","handlingStrategy":"validation","validationCode":"// Browser-side: refuse to call mutating endpoints from a null origin\nif (location.origin === \"null\") throw new Error(\"serve this page over http(s), not file://\");","typeGuard":null,"tryCatchPattern":"if (resp.status === 403 && detail === \"cross-origin request rejected\") {\n  console.error(\"null origin — serve the page from a real origin\");\n}","preventionTips":["Never load control pages from file:// or sandboxed iframes without allow-same-origin","Use the SDK/CLI for automation — non-browser clients send no Origin"],"tags":["security","csrf","origin","http-403","browser"],"backgroundTag":null,"analyzedSha":"322425c43bffde1ed0b64fecf3cf5951565dd82b","analyzedAt":"2026-08-15T01:03:05.481Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}