diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a68ce2c4..3d17613c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ All notable changes to OriginWeave are documented in this file. The format follo ### Added +- Added fail-closed presentation-surface admission so an adapter cannot claim a + privacy profile while any required page-observable field remains ambient. + - Added a proposed privacy-preserving presentation-identity kernel with bounded screen, viewport, pixel ratio, processor, platform, language, reduced-motion, standardized named-UTC time-zone, and credential-free digest contracts; real Chromium application and anti-evasion claims remain explicitly unshipped. - Refreshed the product and technical gap baseline with the 2026-08-24 live inventory: 158 open pull requests (44 ready, 114 draft), refreshed exact base/head evidence for the #208–#222 release, enterprise-approval, BAP, and WARC/PROV chains, the governance issue additions #212 and #215, and a required-check provider-failure record for the fail-closed Strix re-dispatches on #208/#218/#220. diff --git a/crates/originweave-fingerprint/src/lib.rs b/crates/originweave-fingerprint/src/lib.rs index 4aadab6be..150cf768e 100644 --- a/crates/originweave-fingerprint/src/lib.rs +++ b/crates/originweave-fingerprint/src/lib.rs @@ -36,17 +36,30 @@ pub enum PresentationError { InvalidField, /// Cross-field consistency failed (for example viewport exceeds screen). InconsistentIdentity, + /// An adapter cannot override one required observable surface. + MissingSurface(PresentationSurface), } impl fmt::Display for PresentationError { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - let message = match self { - Self::DegenerateSeed => "presentation seed must not be all zero", - Self::InvalidDigest => "digest must be sha256: plus 64 lowercase hex digits", - Self::InvalidField => "presentation field violates its bounded contract", - Self::InconsistentIdentity => "presentation fields contradict each other", - }; - formatter.write_str(message) + match self { + Self::DegenerateSeed => formatter.write_str("presentation seed must not be all zero"), + Self::InvalidDigest => { + formatter.write_str("digest must be sha256: plus 64 lowercase hex digits") + } + Self::InvalidField => { + formatter.write_str("presentation field violates its bounded contract") + } + Self::InconsistentIdentity => { + formatter.write_str("presentation fields contradict each other") + } + Self::MissingSurface(surface) => { + write!( + formatter, + "adapter cannot override required {surface:?} surface" + ) + } + } } } @@ -55,6 +68,53 @@ impl Error for PresentationError {} /// Domain-separation tag for derivation stream expansion. const DERIVE_DOMAIN: &[u8] = b"originweave-presentation/v1"; +/// A page-observable field that an adapter must override before admission. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum PresentationSurface { + /// Screen dimensions and color depth. + Screen, + /// Viewport dimensions. + Viewport, + /// Device pixel ratio. + DevicePixelRatio, + /// Logical processor count. + HardwareConcurrency, + /// Named time-zone identity and offset behavior. + TimeZone, + /// Browser platform family. + Platform, + /// Ordered language preferences. + Languages, + /// Reduced-motion preference. + ReducedMotion, +} + +const REQUIRED_PRESENTATION_SURFACES: [PresentationSurface; 8] = [ + PresentationSurface::Screen, + PresentationSurface::Viewport, + PresentationSurface::DevicePixelRatio, + PresentationSurface::HardwareConcurrency, + PresentationSurface::TimeZone, + PresentationSurface::Platform, + PresentationSurface::Languages, + PresentationSurface::ReducedMotion, +]; + +/// Require an adapter to override every surface claimed by the profile. +/// +/// The first missing surface is returned in stable contract order. Additional +/// or duplicate supported entries do not change admission. +pub fn require_presentation_surfaces( + supported: &[PresentationSurface], +) -> Result<(), PresentationError> { + for required in REQUIRED_PRESENTATION_SURFACES { + if !supported.contains(&required) { + return Err(PresentationError::MissingSurface(required)); + } + } + Ok(()) +} + /// Screen geometry with color depth as pages observe it. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct ScreenMetrics { @@ -673,6 +733,10 @@ mod tests { PresentationError::InconsistentIdentity.to_string(), "presentation fields contradict each other" ); + assert_eq!( + PresentationError::MissingSurface(PresentationSurface::HardwareConcurrency).to_string(), + "adapter cannot override required HardwareConcurrency surface" + ); } #[test] diff --git a/crates/originweave-fingerprint/tests/surface_admission.rs b/crates/originweave-fingerprint/tests/surface_admission.rs new file mode 100644 index 000000000..51fa1e329 --- /dev/null +++ b/crates/originweave-fingerprint/tests/surface_admission.rs @@ -0,0 +1,38 @@ +use originweave_fingerprint::{ + PresentationError, PresentationSurface, require_presentation_surfaces, +}; + +const COMPLETE_SURFACES: [PresentationSurface; 8] = [ + PresentationSurface::Screen, + PresentationSurface::Viewport, + PresentationSurface::DevicePixelRatio, + PresentationSurface::HardwareConcurrency, + PresentationSurface::TimeZone, + PresentationSurface::Platform, + PresentationSurface::Languages, + PresentationSurface::ReducedMotion, +]; + +#[test] +fn incomplete_adapter_support_fails_on_the_first_missing_surface() { + let supported = COMPLETE_SURFACES + .into_iter() + .filter(|surface| *surface != PresentationSurface::HardwareConcurrency) + .collect::>(); + + assert_eq!( + require_presentation_surfaces(&supported), + Err(PresentationError::MissingSurface( + PresentationSurface::HardwareConcurrency + )) + ); +} + +#[test] +fn complete_adapter_support_is_order_and_duplicate_independent() { + let mut supported = COMPLETE_SURFACES.to_vec(); + supported.reverse(); + supported.push(PresentationSurface::Screen); + + assert_eq!(require_presentation_surfaces(&supported), Ok(())); +} diff --git a/docs/TRD.md b/docs/TRD.md index e055396ca..ab7d8a32b 100644 --- a/docs/TRD.md +++ b/docs/TRD.md @@ -189,6 +189,12 @@ surface before page script, preserve the actual engine/platform family, and prove no ambient host fallback. This privacy boundary grants no CAPTCHA, bot-management, or access-control bypass authority. +**Implemented kernel contract; adapter planned.** The kernel admits an adapter +only when it declares every required observable surface and returns the first +missing surface deterministically. Admission is a capability gate, not proof +that BiDi/CDP applied the values; pinned pre-navigation Chromium evidence +remains release-critical. + ## 7. Observation architecture Observation order is an **Accepted architecture** requirement: diff --git a/docs/adr/0110-privacy-preserving-presentation-identity.md b/docs/adr/0110-privacy-preserving-presentation-identity.md index 93627fef4..9e6714e16 100644 --- a/docs/adr/0110-privacy-preserving-presentation-identity.md +++ b/docs/adr/0110-privacy-preserving-presentation-identity.md @@ -49,6 +49,12 @@ remain explicitly ambient and unreleased. The seed, if used for lifecycle selection, is trusted control-plane material and never enters page, model, log, or evidence context. +Before launch, an adapter must pass the kernel's deterministic surface +admission check. Missing screen, viewport, pixel ratio, hardware concurrency, +time zone, platform, language, or reduced-motion support returns the first +missing surface and blocks the claimed profile. Ordering, duplicates, and +unsupported protocol claims cannot relax this boundary. + OriginWeave does not use presentation identity to solve CAPTCHA, impersonate a target person or device, rotate residential routes, defeat bot-management, or circumvent access controls. Such a challenge is recorded as blocked/degraded. @@ -81,9 +87,10 @@ extension, secret, or action authority. Unit and integration tests cover deterministic derivation, independent seed results, enumerated construction, cross-field consistency, standardized UTC -identity, canonical digest validation, and malformed input rejection. Browser -acceptance remains blocked on pinned real-Chromium pre-script injection and -host-fallback evidence. +identity, canonical digest validation, malformed input rejection, complete +surface admission, and exact missing-surface evidence. Browser acceptance +remains blocked on pinned real-Chromium pre-script injection and host-fallback +evidence. ## Migration and rollback diff --git a/docs/doctoring.md b/docs/doctoring.md index 1b4504aaf..4a8598d1f 100644 --- a/docs/doctoring.md +++ b/docs/doctoring.md @@ -35,6 +35,15 @@ before page script and prove that no ambient host value leaks. Camoufox is reviewed only as implementation precedent for native-layer consistency, not as policy authority for anti-detect, CAPTCHA, or access-control circumvention. +The 25 August 2026 WebDriver BiDi Editor's Draft exposes locale, media, screen, +user-agent, viewport, and time-zone emulation commands, but it does not define a +hardware-concurrency override. Chromium's tip-of-tree DevTools Protocol exposes +`Emulation.setHardwareConcurrencyOverride` as Experimental and warns that +tip-of-tree commands can change without notice. OriginWeave therefore records +required presentation surfaces in a protocol-neutral Rust admission contract; +a later pinned Chromium adapter must capability-negotiate every surface and +fail closed before claiming a complete profile. + ### Extension-to-Agent grant origin binding RFC 6454 defines a web origin as the scheme, host, and port tuple that browsers use to isolate authority. An OriginWeave `extension_grant` that is bound only to extension identity, session, and browsing context would remain valid after the same context navigates to another origin. OriginWeave therefore requires the grant and the request to carry the same canonical origin. A host change or a non-default port change is a different origin and cannot reuse the grant. This is grant-scope isolation only; it does not install an extension, parse Chrome messages, or mint Agent capabilities from Manifest V3 permissions. @@ -135,6 +144,8 @@ Bonica, R., Cotton, M., Haberman, B., & Vegoda, L. (2017). *Updates to the speci Cao, Y., Li, S., & Wijmans, E. (2017). (Cross-)browser fingerprinting via OS and hardware level features. *Proceedings of the Network and Distributed System Security Symposium*. https://doi.org/10.14722/ndss.2017.23152 +Chrome DevTools Protocol. (2026). *Emulation domain*. https://chromedevtools.github.io/devtools-protocol/tot/Emulation/ + Chromium Authors. (n.d.). *Proxy support in Chrome* [Source documentation]. Chromium. https://chromium.googlesource.com/chromium/src/+/a3e71ebfa307d8760eb68b777e2998a869940092/net/docs/proxy.md Chromium Authors. (2026). *URL canonicalizer unit tests* [Source code]. Chromium. https://chromium.googlesource.com/chromium/src/+/446d05d21720f0b3505ec21057b3e9f909784262/url/url_canon_unittest.cc @@ -207,6 +218,8 @@ World Wide Web Consortium. (2025, September 25). *Mitigating browser fingerprint World Wide Web Consortium. (2026, June 1). *WebDriver BiDi* (W3C Working Draft). https://www.w3.org/TR/2026/WD-webdriver-bidi-20260601/ +World Wide Web Consortium. (2026, August 25). *WebDriver BiDi* [Editor's Draft]. https://w3c.github.io/webdriver-bidi/ + Xu, J., Sun, Q., Schwendeman, P., Nielsen, S., Cetin, E., & Tang, Y. (2025). *TRINITY: An evolved LLM coordinator* [Preprint]. arXiv. https://doi.org/10.48550/arXiv.2512.04695 Zhou, S., Xu, F. F., Zhu, H., Zhou, X., Lo, R., Sridhar, A., Cheng, X., Ou, T., Bisk, Y., Fried, D., Alon, U., & Neubig, G. (2023). *WebArena: A realistic web environment for building autonomous agents*. arXiv. https://doi.org/10.48550/arXiv.2307.13854 diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 647b0f6e3..c259545b8 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -127,7 +127,7 @@ The hourly product-development loop is operational infrastructure, not proof tha | Priority | Buyer-visible outcome | Protected-main status | Completion issue and acceptance evidence | |---|---|---|---| | P0 | A bounded task observes a real Chromium page, performs one typed action, verifies the post-condition, and emits provenance | **Open / Phase 1** | #28; repeated real Chromium E2E with isolated context, exact session/node authority, typed dispatch, post-condition, crash cleanup, and protected-main checks | -| P1 | A governed browser session minimizes ambient host fingerprint leakage without impersonating a target or bypassing site controls | **Local kernel only; browser integration open** | Proposed ADR 0110 and local `originweave-fingerprint` evidence; acceptance requires a pinned real-Chromium test across UA/client hints/platform/locale/named timezone/screen/DPR/hardware/graphics/fonts/media, pre-script application, lifecycle stability, digest binding, no host fallback, and explicit challenge non-circumvention | +| P1 | A governed browser session minimizes ambient host fingerprint leakage without impersonating a target or bypassing site controls | **Local kernel and surface-admission evidence only; browser integration open** | Proposed ADR 0110 and active stacked `originweave-fingerprint` evidence now fail closed when an adapter omits a required profile surface; acceptance still requires a pinned real-Chromium test across UA/client hints/platform/locale/named timezone/screen/DPR/hardware/graphics/fonts/media, pre-script application, lifecycle stability, digest binding, no host fallback, and explicit challenge non-circumvention | | P0 | Navigation consumes approved origin, resolution, route, TCP peer, TLS identity, bounded HTTP, redirect, MIME, and download policy | **Partial foundation** | #9 plus #28; real browser-network adapter proves the governed path is consumed end to end | | P1 | Existing Chromium extensions remain compatible while Agent authority stays separate | **Partial active-PR evidence** | #27; exact supported-build/platform compatibility matrix, managed allow-list, native-host isolation, repeatability, and release binding | | P1 | Authorized work can use necessary PII without ambient exposure | **Policy foundation; runtime open** | #10; opaque broker, exact field/purpose/destination/model policy, atomic use/revocation, retention/deletion, and value-free telemetry |