# parlov-core
Shared types for HTTP oracle detection. Zero I/O, zero async — just data structures.
## types
```rust
use parlov_core::{ResponseSurface, ProbeDefinition, ProbeSet, OracleResult};
```
**`ResponseSurface`** — one captured HTTP interaction:
```rust
pub struct ResponseSurface {
pub status: StatusCode,
pub headers: HeaderMap,
pub body: Bytes,
pub timing_ns: u64,
}
```
**`ProbeDefinition`** — one HTTP request to execute:
```rust
pub struct ProbeDefinition {
pub url: String,
pub method: Method,
pub headers: HeaderMap, // auth context lives here
pub body: Option<Bytes>,
}
```
**`ProbeSet`** — paired surfaces for differential analysis:
```rust
pub struct ProbeSet {
pub baseline: Vec<ResponseSurface>, // known-valid input
pub probe: Vec<ResponseSurface>, // suspect input
}
```
**`OracleResult`** — the analysis output:
```rust
pub struct OracleResult {
pub class: OracleClass, // Existence, Authentication, Timing, ...
pub verdict: OracleVerdict, // Confirmed / Likely / NotPresent
pub evidence: Vec<String>, // "403 (baseline) vs 404 (probe)"
pub severity: Option<Severity>, // High / Medium / Low
pub label: Option<String>, // "Authorization-based differential"
pub leaks: Option<String>, // "Resource existence confirmed to low-privilege callers"
pub rfc_basis: Option<String>, // "RFC 9110 §15.5.4"
pub baseline_summary: Option<ResponseSummary>, // per-side status on the baseline
pub probe_summary: Option<ResponseSummary>, // per-side status on the probe
pub header_diffs: Vec<DiffedHeader>, // headers that differed between sides
}
```
`label`, `leaks`, `rfc_basis`, `baseline_summary`, and `probe_summary` are omitted from JSON when `None`. `header_diffs` is omitted when empty. All use `skip_serializing_if` and `default` — backward-compatible when deserializing pre-0.3.0 data.
**`DiffedHeader`** — one header that differed between baseline and probe:
```rust
pub struct DiffedHeader {
pub name: String, // lowercase header name, e.g. "x-rate-limit-remaining"
pub baseline: Option<String>, // value on baseline side; None if absent
pub probe: Option<String>, // value on probe side; None if absent
}
```
**`ResponseSummary`** — per-side response summary:
```rust
pub struct ResponseSummary {
pub status: u16, // HTTP status code
}
```
Intentionally minimal — carries only `status` now. Will grow when body diffing lands.
All types derive `Serialize` and `Deserialize` with custom serde helpers for `StatusCode`, `Method`, and `HeaderMap` (the `http` crate types lack native serde support).
## use it
Construct a probe set from captured HTTP interactions:
```rust
use parlov_core::{ProbeSet, ResponseSurface};
use bytes::Bytes;
use http::{HeaderMap, StatusCode};
let baseline = ResponseSurface {
status: StatusCode::FORBIDDEN,
headers: HeaderMap::new(),
body: Bytes::new(),
timing_ns: 12_500_000,
};
let probe = ResponseSurface {
status: StatusCode::NOT_FOUND,
headers: HeaderMap::new(),
body: Bytes::new(),
timing_ns: 11_800_000,
};
let probe_set = ProbeSet {
baseline: vec![baseline],
probe: vec![probe],
};
```
Build a request definition for the probe engine:
```rust
use parlov_core::ProbeDefinition;
use http::{Method, HeaderMap};
let def = ProbeDefinition {
url: "https://api.example.com/users/123".into(),
method: Method::GET,
headers: HeaderMap::new(),
body: None,
};
```
## errors
```rust
use parlov_core::Error;
```
Three variants via `thiserror`: `Http(String)`, `Analysis(String)`, `Serialization(serde_json::Error)`.
## license
MIT OR Apache-2.0