Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 11 additions & 11 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 12 additions & 9 deletions bench/src/livemodels.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -613,20 +613,23 @@ describe("pair qualification configuration", () => {
generatorModel: "z-ai/glm-5.2",
scorerModel: "openai/gpt-5-mini",
};
// Priced an order of magnitude above any admissible profile so the plan is
// refused on projected exposure. Realistic bounds project inside the
// admission ceiling and would exercise the happy path instead.
const pricing = new Map([
[runtimePair.generatorModel, {
providerIdentity: "PinnedProvider",
promptUsdPerToken: 0.00028434,
completionUsdPerToken: 0.00089364,
inputMicrosPerMillionTokens: 284_340,
outputMicrosPerMillionTokens: 893_640,
promptUsdPerToken: 0.0028434,
completionUsdPerToken: 0.0089364,
inputMicrosPerMillionTokens: 2_843_400,
outputMicrosPerMillionTokens: 8_936_400,
}],
[runtimePair.scorerModel, {
providerIdentity: "PinnedProvider",
promptUsdPerToken: 0.00028434,
completionUsdPerToken: 0.00089364,
inputMicrosPerMillionTokens: 284_340,
outputMicrosPerMillionTokens: 893_640,
promptUsdPerToken: 0.0028434,
completionUsdPerToken: 0.0089364,
inputMicrosPerMillionTokens: 2_843_400,
outputMicrosPerMillionTokens: 8_936_400,
}],
]);
try {
Expand All @@ -649,7 +652,7 @@ describe("pair qualification configuration", () => {
apiFormat: "openai-compatible",
costCapUsdDecimal: "70",
upstreamProvider: "PinnedProvider",
})).rejects.toThrow("exceeding the 1000000 micro-dollar operation cap");
})).rejects.toThrow("micro-dollar admission projection cap");
} finally {
if (inheritedModelKey === undefined) delete process.env.MODEL_API_KEY;
else process.env.MODEL_API_KEY = inheritedModelKey;
Expand Down
21 changes: 21 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,28 @@ struct QualificationProfileDigestMaterial<'a> {
repeated_runs: u32,
}

/// Ceiling on what a hosted operation may actually spend, accumulated across
/// provider attempts as they are reserved. This matches the per-review
/// reservation the service holds, so a review can never consume more of an
/// organization's allowance than was set aside for it.
pub const HOSTED_OPERATION_COST_CAP_MICROS: u64 = 1_000_000;

/// Ceiling on what a hosted review may *project* before it runs. Admission
/// prices a worst case rather than an estimate: the full bounded selection of
/// `MAX_HOSTED_SELECTED_BATCHES` batches, every logical call the watchdog plan
/// allows, and a hostile maximum-size retry payload on each one, at the
/// admitted price bounds. The shipped profile projects roughly 15.6 dollars
/// while a review actually spends on the order of 0.01 dollars, so the two
/// quantities differ by three orders of magnitude and cannot share a limit.
///
/// Holding the projection to the spend cap rejects every review before provider
/// contact, whatever its size, and surfaces as a model failure rather than a
/// budget decision. Spend stays bounded by
/// `HOSTED_OPERATION_COST_CAP_MICROS` above, which this deliberately does not
/// relax; `hosted_review_plan_is_admitted_at_shipped_price_bounds` prices the
/// shipped profile at its real bounds so a projection that outgrows this
/// ceiling fails a test instead of every production review.
pub const HOSTED_ADMISSION_PROJECTION_CAP_MICROS: u64 = 25_000_000;
pub const QUALIFICATION_MAX_AGE_DAYS: u32 = 30;
const QUALIFICATION_MAX_AGE_SECONDS: u64 = QUALIFICATION_MAX_AGE_DAYS as u64 * 24 * 60 * 60;
const MAX_SAFE_JSON_INTEGER: u64 = 9_007_199_254_740_991;
Expand Down
34 changes: 34 additions & 0 deletions src/envelope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1735,6 +1735,40 @@ pub(crate) fn incomplete_review_finding(reason: IncompleteReviewReason) -> Findi
}
}

/// The synthetic finding emitted when a review stopped before producing a
/// verdict for a reason that is not model output: an admission limit, a
/// configuration problem, or an unexpected internal error. Postil still fails
/// closed, but the cause is reported as itself. Attributing such a failure to
/// model output sends every reader looking at the model when the model was
/// never called.
pub fn operational_failure_finding(detail: &str) -> Finding {
let detail = detail.trim();
let opening = "Postil could not complete this review, so no verdict was issued.";
let body = if detail.is_empty() || prose_exposes_evidence_boundary(detail) {
opening.to_string()
} else {
format!("{opening}\n\nDetail: {detail}")
};
Finding {
path: OPERATIONAL_PATH.to_string(),
line: 1,
end_line: None,
severity: Severity::Error,
kind: Kind::Uncertainty,
confidence: 1.0,
title: "Review could not be completed".to_string(),
body,
evidence: None,
id: None,
generator_confidence: None,
scorer_confidence: None,
generator_kind: None,
scorer_kind: None,
scorer_reason: None,
repository_claim: None,
}
}

/// The synthetic finding emitted when the model produced unusable output.
/// Postil fails closed: a review that could not be trusted is an error, not a pass.
pub fn fail_closed_finding(detail: &str) -> Finding {
Expand Down
78 changes: 71 additions & 7 deletions src/llm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ use time::Date;

use crate::adjudication::{AdjudicationResult, MAX_ADJUDICATION_OUTPUT_TOKENS};
use crate::api_key;
use crate::config::{ApiFormat, Config, HOSTED_OPERATION_COST_CAP_MICROS, ModelPriceBound};
use crate::config::{
ApiFormat, Config, HOSTED_ADMISSION_PROJECTION_CAP_MICROS, HOSTED_OPERATION_COST_CAP_MICROS,
ModelPriceBound,
};
use crate::envelope::{
Finding, Kind, ModelIncident, ModelIncidentCategory, ModelIncidentPhase, ModelIncidentRecovery,
ModelUsage, ModelUsageCostSource, ModelUsagePhase, ModelUsageRole, ProviderCost,
Expand Down Expand Up @@ -2169,8 +2172,8 @@ impl LlmClient {
.collect::<Vec<_>>()
.join(", ");
ensure!(
exposure.projected_cost_micros <= HOSTED_OPERATION_COST_CAP_MICROS,
"hosted {operation} admission projects {} micro-dollars of provider exposure across {} attempts, {} serialized input bytes, and {} output tokens (per-model micro-dollars: {model_costs}), exceeding the {HOSTED_OPERATION_COST_CAP_MICROS} micro-dollar operation cap",
exposure.projected_cost_micros <= HOSTED_ADMISSION_PROJECTION_CAP_MICROS,
"hosted {operation} admission projects {} micro-dollars of provider exposure across {} attempts, {} serialized input bytes, and {} output tokens (per-model micro-dollars: {model_costs}), exceeding the {HOSTED_ADMISSION_PROJECTION_CAP_MICROS} micro-dollar admission projection cap",
exposure.projected_cost_micros,
exposure.attempts,
exposure.input_bytes,
Expand Down Expand Up @@ -8040,6 +8043,64 @@ mod tests {
assert_eq!(client.admission.lock().unwrap().attempts, 0);
}

/// The shipped provisional hosted profile must actually clear the operation
/// cost cap. The neighbouring plan test prices every token at one micro per
/// million, so it cannot observe the cap at all; this one uses the real
/// admitted price bounds, which is the only way a cap that rejects every
/// production review shows up as a test failure rather than an outage.
#[test]
fn hosted_review_plan_is_admitted_at_shipped_price_bounds() {
let config = Config {
model: "z-ai/glm-5.2".into(),
scorer_enabled: false,
..Config::default()
};
let mut client = LlmClient::build(
&config,
"test-key".into(),
Duration::from_secs(1),
None,
None,
)
.unwrap();
client.request_decorations.hosted_price_bounds = Some(Arc::new(HashMap::from([(
"z-ai/glm-5.2".into(),
ModelPriceBound {
model: "z-ai/glm-5.2".into(),
input_micros_per_million_tokens: 1_400_000,
output_micros_per_million_tokens: 4_400_000,
},
)])));
let users =
vec!["bounded candidate".to_string(); crate::review::MAX_HOSTED_SELECTED_BATCHES];
let output_tokens = vec![REVIEW_MAX_TOKENS; crate::review::MAX_HOSTED_SELECTED_BATCHES];
let manifest = "m".repeat(96_000);
let admission = client
.preflight_review_plan_with_output_limits(
&config,
crate::review::MAX_HOSTED_SELECTED_BATCHES,
"system",
ReviewPreflightPrompts {
first_users: &users,
later_users: &users,
output_tokens: &output_tokens,
scorer_system: "scorer system",
current_utc_date: trusted_date(),
},
ReviewPlanSchedule {
planner: Some((&manifest, 1)),
batch_concurrency: 1,
},
)
.expect("the shipped hosted profile must be admissible");
assert!(
admission.projected_cost_micros <= HOSTED_ADMISSION_PROJECTION_CAP_MICROS,
"projected {} exceeds the {} admission cap",
admission.projected_cost_micros,
HOSTED_ADMISSION_PROJECTION_CAP_MICROS
);
}

#[test]
fn maximum_hosted_plan_matches_watchdog_and_transport_arithmetic() {
let config = Config {
Expand Down Expand Up @@ -8282,10 +8343,10 @@ mod tests {
attempts: 6,
input_bytes: 12_345,
output_tokens: 678,
projected_cost_micros: HOSTED_OPERATION_COST_CAP_MICROS + 1,
projected_cost_micros: HOSTED_ADMISSION_PROJECTION_CAP_MICROS + 1,
model_costs_micros: BTreeMap::from([(
"provider/model".to_string(),
HOSTED_OPERATION_COST_CAP_MICROS + 1,
HOSTED_ADMISSION_PROJECTION_CAP_MICROS + 1,
)]),
},
)
Expand All @@ -8294,7 +8355,10 @@ mod tests {
assert!(message.contains("provider exposure across 6 attempts"));
assert!(message.contains("12345 serialized input bytes"));
assert!(message.contains("678 output tokens"));
assert!(message.contains(r#""provider/model"=1000001"#));
assert!(message.contains(&format!(
r#""provider/model"={}"#,
HOSTED_ADMISSION_PROJECTION_CAP_MICROS + 1
)));
}

#[test]
Expand Down Expand Up @@ -8332,7 +8396,7 @@ mod tests {
);
assert_eq!(exposure.projected_cost_micros, 1_056);

exposure.projected_cost_micros = HOSTED_OPERATION_COST_CAP_MICROS + 1;
exposure.projected_cost_micros = HOSTED_ADMISSION_PROJECTION_CAP_MICROS + 1;
let error = LlmClient::build(
&Config::default(),
"test-key".into(),
Expand Down
Loading