mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-10-10 03:30:59 +00:00
Fix 10 OpenAPI review items for HITL, run outputs, and verifications
Addresses agreed items from the openapi-hitl-and-run-outputs review: rename retrieveRunDiff operationId, add 409s to steer/preview, bound expires_in_secs, add selected_option_keys for multi-select end-to-end, document skip/na semantics, add slug and require type on RunVerificationControl, require file on CodeLocation, and remove the checkpoint "all" sentinel in favor of omitting the parameter. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
a519124532
commit
72c0c8e257
16 changed files with 175 additions and 96 deletions
|
|
@ -14,7 +14,7 @@ import type { Route } from "./+types/run-compare";
|
|||
export const handle = { wide: true };
|
||||
|
||||
export async function loader({ request, params }: Route.LoaderArgs) {
|
||||
const data = await apiJson<RunCompare>(`/runs/${params.id}/compare?checkpoint=all`, { request });
|
||||
const data = await apiJson<RunCompare>(`/runs/${params.id}/compare`, { request });
|
||||
return data;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -946,7 +946,6 @@ mod runs {
|
|||
pub fn compare() -> RunCompare {
|
||||
RunCompare {
|
||||
checkpoints: vec![
|
||||
FileCheckpoint { id: "all".into(), label: "All changes".into() },
|
||||
FileCheckpoint { id: "cp-4".into(), label: "Checkpoint 4 — Apply Changes".into() },
|
||||
FileCheckpoint { id: "cp-3".into(), label: "Checkpoint 3 — Review Changes".into() },
|
||||
FileCheckpoint { id: "cp-2".into(), label: "Checkpoint 2 — Propose Changes".into() },
|
||||
|
|
@ -1454,7 +1453,7 @@ mod verifications {
|
|||
name: &'static str,
|
||||
slug: &'static str,
|
||||
description: &'static str,
|
||||
type_: Option<VerificationType>,
|
||||
type_: VerificationType,
|
||||
mode: VerificationMode,
|
||||
f1: Option<f64>,
|
||||
pass_at_1: Option<f64>,
|
||||
|
|
@ -1640,7 +1639,7 @@ mod verifications {
|
|||
ControlDef {
|
||||
name: "Motivation", slug: "motivation",
|
||||
description: "Origin of proposal identified",
|
||||
type_: Some(VerificationType::Ai), mode: VerificationMode::Active,
|
||||
type_: VerificationType::Ai, mode: VerificationMode::Active,
|
||||
f1: Some(0.87), pass_at_1: Some(0.82),
|
||||
evaluations: &[P, P, F, P, P, P, P, F, P, P],
|
||||
run_status: VerificationResult::Pass,
|
||||
|
|
@ -1653,7 +1652,7 @@ mod verifications {
|
|||
ControlDef {
|
||||
name: "Specifications", slug: "specifications",
|
||||
description: "Requirements written down",
|
||||
type_: Some(VerificationType::Ai), mode: VerificationMode::Active,
|
||||
type_: VerificationType::Ai, mode: VerificationMode::Active,
|
||||
f1: Some(0.83), pass_at_1: Some(0.78),
|
||||
evaluations: &[P, F, P, P, P, F, P, P, P, P],
|
||||
run_status: VerificationResult::Pass,
|
||||
|
|
@ -1666,7 +1665,7 @@ mod verifications {
|
|||
ControlDef {
|
||||
name: "Documentation", slug: "documentation",
|
||||
description: "Developer and user docs added",
|
||||
type_: Some(VerificationType::Ai), mode: VerificationMode::Active,
|
||||
type_: VerificationType::Ai, mode: VerificationMode::Active,
|
||||
f1: Some(0.79), pass_at_1: Some(0.74),
|
||||
evaluations: &[P, P, P, F, P, P, F, P, P, F],
|
||||
run_status: VerificationResult::Pass,
|
||||
|
|
@ -1679,7 +1678,7 @@ mod verifications {
|
|||
ControlDef {
|
||||
name: "Minimization", slug: "minimization",
|
||||
description: "No extraneous changes",
|
||||
type_: Some(VerificationType::Ai), mode: VerificationMode::Evaluate,
|
||||
type_: VerificationType::Ai, mode: VerificationMode::Evaluate,
|
||||
f1: Some(0.72), pass_at_1: Some(0.68),
|
||||
evaluations: &[P, F, P, F, P, P, F, P, P, P],
|
||||
run_status: VerificationResult::Pass,
|
||||
|
|
@ -1698,7 +1697,7 @@ mod verifications {
|
|||
ControlDef {
|
||||
name: "Formatting", slug: "formatting",
|
||||
description: "Code layout matches standard",
|
||||
type_: Some(VerificationType::Automated), mode: VerificationMode::Active,
|
||||
type_: VerificationType::Automated, mode: VerificationMode::Active,
|
||||
f1: Some(0.99), pass_at_1: Some(0.98),
|
||||
evaluations: &[P, P, P, P, P, P, P, P, P, P],
|
||||
run_status: VerificationResult::Pass,
|
||||
|
|
@ -1711,7 +1710,7 @@ mod verifications {
|
|||
ControlDef {
|
||||
name: "Linting", slug: "linting",
|
||||
description: "Linter issues resolved",
|
||||
type_: Some(VerificationType::Automated), mode: VerificationMode::Active,
|
||||
type_: VerificationType::Automated, mode: VerificationMode::Active,
|
||||
f1: Some(0.98), pass_at_1: Some(0.97),
|
||||
evaluations: &[P, P, P, P, P, P, P, P, F, P],
|
||||
run_status: VerificationResult::Pass,
|
||||
|
|
@ -1724,7 +1723,7 @@ mod verifications {
|
|||
ControlDef {
|
||||
name: "Style", slug: "style",
|
||||
description: "House style applied",
|
||||
type_: Some(VerificationType::Ai), mode: VerificationMode::Active,
|
||||
type_: VerificationType::Ai, mode: VerificationMode::Active,
|
||||
f1: Some(0.81), pass_at_1: Some(0.76),
|
||||
evaluations: &[P, F, P, P, P, P, F, P, P, P],
|
||||
run_status: VerificationResult::Pass,
|
||||
|
|
@ -1743,7 +1742,7 @@ mod verifications {
|
|||
ControlDef {
|
||||
name: "Completeness", slug: "completeness",
|
||||
description: "Implementation covers requirements",
|
||||
type_: Some(VerificationType::Ai), mode: VerificationMode::Active,
|
||||
type_: VerificationType::Ai, mode: VerificationMode::Active,
|
||||
f1: Some(0.76), pass_at_1: Some(0.71),
|
||||
evaluations: &[P, P, F, P, F, P, P, P, F, P],
|
||||
run_status: VerificationResult::Pass,
|
||||
|
|
@ -1756,7 +1755,7 @@ mod verifications {
|
|||
ControlDef {
|
||||
name: "Defects", slug: "defects",
|
||||
description: "Potential or likely bugs remediated",
|
||||
type_: Some(VerificationType::AiAnalysis), mode: VerificationMode::Active,
|
||||
type_: VerificationType::AiAnalysis, mode: VerificationMode::Active,
|
||||
f1: Some(0.84), pass_at_1: Some(0.79),
|
||||
evaluations: &[P, P, P, F, P, P, P, P, P, F],
|
||||
run_status: VerificationResult::Pass,
|
||||
|
|
@ -1769,7 +1768,7 @@ mod verifications {
|
|||
ControlDef {
|
||||
name: "Performance", slug: "performance",
|
||||
description: "Hot path impact identified",
|
||||
type_: Some(VerificationType::Ai), mode: VerificationMode::Evaluate,
|
||||
type_: VerificationType::Ai, mode: VerificationMode::Evaluate,
|
||||
f1: Some(0.69), pass_at_1: Some(0.63),
|
||||
evaluations: &[F, P, P, F, P, F, P, P, F, P],
|
||||
run_status: VerificationResult::Pass,
|
||||
|
|
@ -1788,7 +1787,7 @@ mod verifications {
|
|||
ControlDef {
|
||||
name: "Test Coverage", slug: "test-coverage",
|
||||
description: "Production code exercised by unit tests",
|
||||
type_: Some(VerificationType::Analysis), mode: VerificationMode::Active,
|
||||
type_: VerificationType::Analysis, mode: VerificationMode::Active,
|
||||
f1: Some(0.95), pass_at_1: Some(0.93),
|
||||
evaluations: &[P, P, P, P, P, P, F, P, P, P],
|
||||
run_status: VerificationResult::Pass,
|
||||
|
|
@ -1801,7 +1800,7 @@ mod verifications {
|
|||
ControlDef {
|
||||
name: "Test Quality", slug: "test-quality",
|
||||
description: "Tests are robust and clear",
|
||||
type_: Some(VerificationType::Ai), mode: VerificationMode::Evaluate,
|
||||
type_: VerificationType::Ai, mode: VerificationMode::Evaluate,
|
||||
f1: Some(0.71), pass_at_1: Some(0.65),
|
||||
evaluations: &[P, F, F, P, P, F, P, F, P, P],
|
||||
run_status: VerificationResult::Fail,
|
||||
|
|
@ -1814,7 +1813,7 @@ mod verifications {
|
|||
ControlDef {
|
||||
name: "E2E Coverage", slug: "e2e-coverage",
|
||||
description: "Browser automation exercises UX",
|
||||
type_: Some(VerificationType::Analysis), mode: VerificationMode::Active,
|
||||
type_: VerificationType::Analysis, mode: VerificationMode::Active,
|
||||
f1: Some(0.91), pass_at_1: Some(0.88),
|
||||
evaluations: &[P, P, P, F, P, P, P, P, P, P],
|
||||
run_status: VerificationResult::Na,
|
||||
|
|
@ -1833,7 +1832,7 @@ mod verifications {
|
|||
ControlDef {
|
||||
name: "Architecture", slug: "architecture",
|
||||
description: "Layering and dependency graph meets design",
|
||||
type_: Some(VerificationType::Analysis), mode: VerificationMode::Active,
|
||||
type_: VerificationType::Analysis, mode: VerificationMode::Active,
|
||||
f1: Some(0.88), pass_at_1: Some(0.84),
|
||||
evaluations: &[P, P, P, P, F, P, P, P, P, P],
|
||||
run_status: VerificationResult::Pass,
|
||||
|
|
@ -1846,7 +1845,7 @@ mod verifications {
|
|||
ControlDef {
|
||||
name: "Interfaces", slug: "interfaces",
|
||||
description: "",
|
||||
type_: None, mode: VerificationMode::Disabled,
|
||||
type_: VerificationType::Ai, mode: VerificationMode::Disabled,
|
||||
f1: None, pass_at_1: None,
|
||||
evaluations: &[],
|
||||
run_status: VerificationResult::Pass,
|
||||
|
|
@ -1859,7 +1858,7 @@ mod verifications {
|
|||
ControlDef {
|
||||
name: "Duplication", slug: "duplication",
|
||||
description: "Similar and identical code blocks identified",
|
||||
type_: Some(VerificationType::Analysis), mode: VerificationMode::Active,
|
||||
type_: VerificationType::Analysis, mode: VerificationMode::Active,
|
||||
f1: Some(0.96), pass_at_1: Some(0.94),
|
||||
evaluations: &[P, P, P, P, P, P, P, F, P, P],
|
||||
run_status: VerificationResult::Pass,
|
||||
|
|
@ -1872,7 +1871,7 @@ mod verifications {
|
|||
ControlDef {
|
||||
name: "Simplicity", slug: "simplicity",
|
||||
description: "Extra review for reducing complexity",
|
||||
type_: Some(VerificationType::Ai), mode: VerificationMode::Active,
|
||||
type_: VerificationType::Ai, mode: VerificationMode::Active,
|
||||
f1: Some(0.74), pass_at_1: Some(0.69),
|
||||
evaluations: &[P, F, P, P, F, P, P, F, P, P],
|
||||
run_status: VerificationResult::Pass,
|
||||
|
|
@ -1885,7 +1884,7 @@ mod verifications {
|
|||
ControlDef {
|
||||
name: "Dead Code", slug: "dead-code",
|
||||
description: "Unexecuted code and dependencies removed",
|
||||
type_: Some(VerificationType::Analysis), mode: VerificationMode::Active,
|
||||
type_: VerificationType::Analysis, mode: VerificationMode::Active,
|
||||
f1: Some(0.93), pass_at_1: Some(0.90),
|
||||
evaluations: &[P, P, P, P, P, F, P, P, P, P],
|
||||
run_status: VerificationResult::Pass,
|
||||
|
|
@ -1904,7 +1903,7 @@ mod verifications {
|
|||
ControlDef {
|
||||
name: "Vulnerabilities", slug: "vulnerabilities",
|
||||
description: "Security issues are remediated",
|
||||
type_: Some(VerificationType::AiAnalysis), mode: VerificationMode::Active,
|
||||
type_: VerificationType::AiAnalysis, mode: VerificationMode::Active,
|
||||
f1: Some(0.86), pass_at_1: Some(0.81),
|
||||
evaluations: &[P, P, F, P, P, P, P, P, F, P],
|
||||
run_status: VerificationResult::Pass,
|
||||
|
|
@ -1917,7 +1916,7 @@ mod verifications {
|
|||
ControlDef {
|
||||
name: "IaC Scanning", slug: "iac-scanning",
|
||||
description: "",
|
||||
type_: None, mode: VerificationMode::Disabled,
|
||||
type_: VerificationType::Automated, mode: VerificationMode::Disabled,
|
||||
f1: None, pass_at_1: None,
|
||||
evaluations: &[],
|
||||
run_status: VerificationResult::Pass,
|
||||
|
|
@ -1930,7 +1929,7 @@ mod verifications {
|
|||
ControlDef {
|
||||
name: "Dependency Alerts", slug: "dependency-alerts",
|
||||
description: "Known CVEs are patched",
|
||||
type_: Some(VerificationType::Analysis), mode: VerificationMode::Active,
|
||||
type_: VerificationType::Analysis, mode: VerificationMode::Active,
|
||||
f1: Some(0.97), pass_at_1: Some(0.95),
|
||||
evaluations: &[P, P, P, P, P, P, P, P, P, F],
|
||||
run_status: VerificationResult::Pass,
|
||||
|
|
@ -1943,7 +1942,7 @@ mod verifications {
|
|||
ControlDef {
|
||||
name: "Security Controls", slug: "security-controls",
|
||||
description: "Organization standards applied",
|
||||
type_: Some(VerificationType::Ai), mode: VerificationMode::Active,
|
||||
type_: VerificationType::Ai, mode: VerificationMode::Active,
|
||||
f1: Some(0.80), pass_at_1: Some(0.75),
|
||||
evaluations: &[P, P, F, P, P, F, P, P, P, P],
|
||||
run_status: VerificationResult::Pass,
|
||||
|
|
@ -1962,7 +1961,7 @@ mod verifications {
|
|||
ControlDef {
|
||||
name: "Compatibility", slug: "compatibility",
|
||||
description: "Breaking changes are avoided",
|
||||
type_: Some(VerificationType::Analysis), mode: VerificationMode::Active,
|
||||
type_: VerificationType::Analysis, mode: VerificationMode::Active,
|
||||
f1: Some(0.89), pass_at_1: Some(0.85),
|
||||
evaluations: &[P, P, P, P, F, P, P, P, P, P],
|
||||
run_status: VerificationResult::Pass,
|
||||
|
|
@ -1975,7 +1974,7 @@ mod verifications {
|
|||
ControlDef {
|
||||
name: "Rollout / Rollback", slug: "rollout-rollback",
|
||||
description: "Known rollback plan if deploy fails",
|
||||
type_: Some(VerificationType::Ai), mode: VerificationMode::Evaluate,
|
||||
type_: VerificationType::Ai, mode: VerificationMode::Evaluate,
|
||||
f1: Some(0.66), pass_at_1: Some(0.60),
|
||||
evaluations: &[F, P, F, P, F, P, P, F, P, F],
|
||||
run_status: VerificationResult::Fail,
|
||||
|
|
@ -1988,7 +1987,7 @@ mod verifications {
|
|||
ControlDef {
|
||||
name: "Observability", slug: "observability",
|
||||
description: "Logging, metrics, tracing instrumented",
|
||||
type_: Some(VerificationType::Ai), mode: VerificationMode::Evaluate,
|
||||
type_: VerificationType::Ai, mode: VerificationMode::Evaluate,
|
||||
f1: Some(0.73), pass_at_1: Some(0.67),
|
||||
evaluations: &[P, F, P, F, P, P, F, P, F, P],
|
||||
run_status: VerificationResult::Fail,
|
||||
|
|
@ -2001,7 +2000,7 @@ mod verifications {
|
|||
ControlDef {
|
||||
name: "Cost", slug: "cost",
|
||||
description: "Tech ops costs estimated",
|
||||
type_: Some(VerificationType::Analysis), mode: VerificationMode::Evaluate,
|
||||
type_: VerificationType::Analysis, mode: VerificationMode::Evaluate,
|
||||
f1: Some(0.78), pass_at_1: Some(0.72),
|
||||
evaluations: &[P, P, F, P, F, P, P, F, P, P],
|
||||
run_status: VerificationResult::Pass,
|
||||
|
|
@ -2020,7 +2019,7 @@ mod verifications {
|
|||
ControlDef {
|
||||
name: "Change Control", slug: "change-control",
|
||||
description: "Separation of Duties policy met",
|
||||
type_: Some(VerificationType::Analysis), mode: VerificationMode::Active,
|
||||
type_: VerificationType::Analysis, mode: VerificationMode::Active,
|
||||
f1: Some(0.94), pass_at_1: Some(0.91),
|
||||
evaluations: &[P, P, P, P, P, P, P, P, F, P],
|
||||
run_status: VerificationResult::Pass,
|
||||
|
|
@ -2033,7 +2032,7 @@ mod verifications {
|
|||
ControlDef {
|
||||
name: "AI Governance", slug: "ai-governance",
|
||||
description: "AI involvement was acceptable",
|
||||
type_: Some(VerificationType::Analysis), mode: VerificationMode::Active,
|
||||
type_: VerificationType::Analysis, mode: VerificationMode::Active,
|
||||
f1: Some(0.85), pass_at_1: Some(0.80),
|
||||
evaluations: &[P, P, P, F, P, P, P, P, P, P],
|
||||
run_status: VerificationResult::Pass,
|
||||
|
|
@ -2046,7 +2045,7 @@ mod verifications {
|
|||
ControlDef {
|
||||
name: "Privacy", slug: "privacy",
|
||||
description: "PII is identified and handled to standards",
|
||||
type_: Some(VerificationType::Ai), mode: VerificationMode::Active,
|
||||
type_: VerificationType::Ai, mode: VerificationMode::Active,
|
||||
f1: Some(0.77), pass_at_1: Some(0.72),
|
||||
evaluations: &[P, F, P, P, P, F, P, P, P, F],
|
||||
run_status: VerificationResult::Pass,
|
||||
|
|
@ -2059,7 +2058,7 @@ mod verifications {
|
|||
ControlDef {
|
||||
name: "Accessibility", slug: "accessibility",
|
||||
description: "Software meets accessibility requirements",
|
||||
type_: Some(VerificationType::Analysis), mode: VerificationMode::Active,
|
||||
type_: VerificationType::Analysis, mode: VerificationMode::Active,
|
||||
f1: Some(0.90), pass_at_1: Some(0.87),
|
||||
evaluations: &[P, P, P, P, P, F, P, P, P, P],
|
||||
run_status: VerificationResult::Pass,
|
||||
|
|
@ -2072,7 +2071,7 @@ mod verifications {
|
|||
ControlDef {
|
||||
name: "Licensing", slug: "licensing",
|
||||
description: "Supply chain meets IP policy",
|
||||
type_: Some(VerificationType::Analysis), mode: VerificationMode::Active,
|
||||
type_: VerificationType::Analysis, mode: VerificationMode::Active,
|
||||
f1: Some(0.96), pass_at_1: Some(0.93),
|
||||
evaluations: &[P, P, P, P, P, P, P, P, P, P],
|
||||
run_status: VerificationResult::Pass,
|
||||
|
|
@ -2155,7 +2154,7 @@ mod verifications {
|
|||
.map(|(_, s)| SiblingControl {
|
||||
name: s.name.into(),
|
||||
slug: s.slug.into(),
|
||||
type_: s.type_,
|
||||
type_: Some(s.type_),
|
||||
mode: Some(s.mode),
|
||||
})
|
||||
.collect();
|
||||
|
|
@ -2170,7 +2169,7 @@ mod verifications {
|
|||
name: ctrl.name.into(),
|
||||
slug: ctrl.slug.into(),
|
||||
description: ctrl.description.into(),
|
||||
type_: ctrl.type_,
|
||||
type_: Some(ctrl.type_),
|
||||
category: CategoryReference { name: cat.name.into() },
|
||||
},
|
||||
performance: ControlPerformance {
|
||||
|
|
@ -2206,6 +2205,7 @@ mod verifications {
|
|||
.iter()
|
||||
.map(|c| RunVerificationControl {
|
||||
name: c.name.into(),
|
||||
slug: c.slug.into(),
|
||||
description: c.description.into(),
|
||||
type_: c.type_,
|
||||
status: c.run_status,
|
||||
|
|
|
|||
|
|
@ -767,30 +767,42 @@ async fn submit_answer(
|
|||
.into_response();
|
||||
}
|
||||
};
|
||||
let answer = match &req.selected_option_key {
|
||||
Some(key) => {
|
||||
let option = interviewer
|
||||
.pending_questions()
|
||||
.iter()
|
||||
.find(|pq| pq.id == qid)
|
||||
.and_then(|pq| pq.question.options.iter().find(|o| o.key == *key))
|
||||
.cloned();
|
||||
match option {
|
||||
Some(opt) => Answer::selected(key.clone(), opt),
|
||||
let answer = if let Some(key) = &req.selected_option_key {
|
||||
let option = interviewer
|
||||
.pending_questions()
|
||||
.iter()
|
||||
.find(|pq| pq.id == qid)
|
||||
.and_then(|pq| pq.question.options.iter().find(|o| o.key == *key))
|
||||
.cloned();
|
||||
match option {
|
||||
Some(opt) => Answer::selected(key.clone(), opt),
|
||||
None => {
|
||||
return ApiError::bad_request("Invalid option key.").into_response();
|
||||
}
|
||||
}
|
||||
} else if !req.selected_option_keys.is_empty() {
|
||||
let pending = interviewer.pending_questions();
|
||||
let pq = pending.iter().find(|pq| pq.id == qid);
|
||||
let mut options = Vec::new();
|
||||
for key in &req.selected_option_keys {
|
||||
let opt = pq.and_then(|pq| {
|
||||
pq.question.options.iter().find(|o| o.key == *key).cloned()
|
||||
});
|
||||
match opt {
|
||||
Some(o) => options.push(o),
|
||||
None => {
|
||||
return ApiError::bad_request("Invalid option key.").into_response();
|
||||
}
|
||||
}
|
||||
}
|
||||
None => match req.value {
|
||||
Some(v) => Answer::text(v),
|
||||
None => {
|
||||
return ApiError::bad_request(
|
||||
"Either value or selected_option_key is required.",
|
||||
)
|
||||
.into_response();
|
||||
}
|
||||
},
|
||||
Answer::multi_selected(req.selected_option_keys, options)
|
||||
} else if let Some(v) = req.value {
|
||||
Answer::text(v)
|
||||
} else {
|
||||
return ApiError::bad_request(
|
||||
"One of value, selected_option_key, or selected_option_keys is required.",
|
||||
)
|
||||
.into_response();
|
||||
};
|
||||
let accepted = interviewer.submit_answer(&qid, answer);
|
||||
if accepted {
|
||||
|
|
|
|||
|
|
@ -86,6 +86,7 @@ fn format_answer(answer: &Answer) -> String {
|
|||
k.clone()
|
||||
}
|
||||
}
|
||||
AnswerValue::MultiSelected(keys) => keys.join(", "),
|
||||
AnswerValue::Skipped => "Skipped".to_string(),
|
||||
AnswerValue::Timeout => "Timed out".to_string(),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -255,6 +255,7 @@ fn answer_text(answer: &Answer) -> String {
|
|||
match &answer.value {
|
||||
AnswerValue::Text(t) => t.clone(),
|
||||
AnswerValue::Selected(s) => s.clone(),
|
||||
AnswerValue::MultiSelected(keys) => keys.join(", "),
|
||||
AnswerValue::Yes => "yes".to_string(),
|
||||
AnswerValue::No => "no".to_string(),
|
||||
AnswerValue::Skipped => "skipped".to_string(),
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ impl Interviewer for AutoApproveInterviewer {
|
|||
|first| Answer {
|
||||
value: AnswerValue::Selected(first.key.clone()),
|
||||
selected_option: Some(first.clone()),
|
||||
selected_options: Vec::new(),
|
||||
text: None,
|
||||
},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ fn find_matching_option(response: &str, options: &[super::QuestionOption]) -> Op
|
|||
return Some(Answer {
|
||||
value: AnswerValue::Selected(opt.key.clone()),
|
||||
selected_option: Some(opt.clone()),
|
||||
selected_options: Vec::new(),
|
||||
text: None,
|
||||
});
|
||||
}
|
||||
|
|
@ -39,6 +40,7 @@ fn find_matching_option(response: &str, options: &[super::QuestionOption]) -> Op
|
|||
return Some(Answer {
|
||||
value: AnswerValue::Selected(opt.key.clone()),
|
||||
selected_option: Some(opt.clone()),
|
||||
selected_options: Vec::new(),
|
||||
text: None,
|
||||
});
|
||||
}
|
||||
|
|
@ -89,6 +91,7 @@ fn ask_select_interactive(question: &Question) -> Answer {
|
|||
Answer {
|
||||
value: AnswerValue::Selected(opt.key.clone()),
|
||||
selected_option: Some(opt.clone()),
|
||||
selected_options: Vec::new(),
|
||||
text: None,
|
||||
}
|
||||
}
|
||||
|
|
@ -111,13 +114,9 @@ fn ask_multi_select_interactive(question: &Question) -> Answer {
|
|||
|
||||
match selection {
|
||||
Ok(Some(indices)) if !indices.is_empty() => {
|
||||
let idx = indices[0];
|
||||
let opt = &question.options[idx];
|
||||
Answer {
|
||||
value: AnswerValue::Selected(opt.key.clone()),
|
||||
selected_option: Some(opt.clone()),
|
||||
text: None,
|
||||
}
|
||||
let keys: Vec<String> = indices.iter().map(|&i| question.options[i].key.clone()).collect();
|
||||
let options: Vec<_> = indices.iter().map(|&i| question.options[i].clone()).collect();
|
||||
Answer::multi_selected(keys, options)
|
||||
}
|
||||
_ => Answer::skipped(),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@ pub enum AnswerValue {
|
|||
Skipped,
|
||||
Timeout,
|
||||
Selected(String),
|
||||
MultiSelected(Vec<String>),
|
||||
Text(String),
|
||||
}
|
||||
|
||||
|
|
@ -84,42 +85,48 @@ pub enum AnswerValue {
|
|||
pub struct Answer {
|
||||
pub value: AnswerValue,
|
||||
pub selected_option: Option<QuestionOption>,
|
||||
#[serde(default)]
|
||||
pub selected_options: Vec<QuestionOption>,
|
||||
pub text: Option<String>,
|
||||
}
|
||||
|
||||
impl Answer {
|
||||
#[must_use]
|
||||
pub const fn yes() -> Self {
|
||||
pub fn yes() -> Self {
|
||||
Self {
|
||||
value: AnswerValue::Yes,
|
||||
selected_option: None,
|
||||
selected_options: Vec::new(),
|
||||
text: None,
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn no() -> Self {
|
||||
pub fn no() -> Self {
|
||||
Self {
|
||||
value: AnswerValue::No,
|
||||
selected_option: None,
|
||||
selected_options: Vec::new(),
|
||||
text: None,
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn skipped() -> Self {
|
||||
pub fn skipped() -> Self {
|
||||
Self {
|
||||
value: AnswerValue::Skipped,
|
||||
selected_option: None,
|
||||
selected_options: Vec::new(),
|
||||
text: None,
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn timeout() -> Self {
|
||||
pub fn timeout() -> Self {
|
||||
Self {
|
||||
value: AnswerValue::Timeout,
|
||||
selected_option: None,
|
||||
selected_options: Vec::new(),
|
||||
text: None,
|
||||
}
|
||||
}
|
||||
|
|
@ -129,6 +136,16 @@ impl Answer {
|
|||
Self {
|
||||
value: AnswerValue::Selected(key),
|
||||
selected_option: Some(option),
|
||||
selected_options: Vec::new(),
|
||||
text: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn multi_selected(keys: Vec<String>, options: Vec<QuestionOption>) -> Self {
|
||||
Self {
|
||||
value: AnswerValue::MultiSelected(keys),
|
||||
selected_option: None,
|
||||
selected_options: options,
|
||||
text: None,
|
||||
}
|
||||
}
|
||||
|
|
@ -138,6 +155,7 @@ impl Answer {
|
|||
Self {
|
||||
value: AnswerValue::Text(t.clone()),
|
||||
selected_option: None,
|
||||
selected_options: Vec::new(),
|
||||
text: Some(t),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -435,6 +435,7 @@ async fn end_to_end_human_gate_pipeline() {
|
|||
let answers = VecDeque::from([Answer {
|
||||
value: AnswerValue::Selected("R".to_string()),
|
||||
selected_option: None,
|
||||
selected_options: Vec::new(),
|
||||
text: None,
|
||||
}]);
|
||||
let interviewer = Arc::new(QueueInterviewer::new(answers));
|
||||
|
|
@ -2151,11 +2152,13 @@ async fn human_gate_loops_back() {
|
|||
Answer {
|
||||
value: AnswerValue::Selected("F".to_string()),
|
||||
selected_option: None,
|
||||
selected_options: Vec::new(),
|
||||
text: None,
|
||||
},
|
||||
Answer {
|
||||
value: AnswerValue::Selected("A".to_string()),
|
||||
selected_option: None,
|
||||
selected_options: Vec::new(),
|
||||
text: None,
|
||||
},
|
||||
]);
|
||||
|
|
@ -6193,6 +6196,7 @@ async fn human_gate_freeform_with_fixed_choice_match() {
|
|||
let answers = VecDeque::from([Answer {
|
||||
value: AnswerValue::Selected("A".to_string()),
|
||||
selected_option: None,
|
||||
selected_options: Vec::new(),
|
||||
text: None,
|
||||
}]);
|
||||
let interviewer = Arc::new(QueueInterviewer::new(answers));
|
||||
|
|
@ -6434,6 +6438,7 @@ async fn human_gate_freeform_sets_allow_freeform_on_question() {
|
|||
let answers = VecDeque::from([Answer {
|
||||
value: AnswerValue::Selected("A".to_string()),
|
||||
selected_option: None,
|
||||
selected_options: Vec::new(),
|
||||
text: None,
|
||||
}]);
|
||||
let inner = QueueInterviewer::new(answers);
|
||||
|
|
@ -6542,6 +6547,7 @@ async fn human_gate_without_freeform_sets_allow_freeform_false() {
|
|||
let answers = VecDeque::from([Answer {
|
||||
value: AnswerValue::Selected("A".to_string()),
|
||||
selected_option: None,
|
||||
selected_options: Vec::new(),
|
||||
text: None,
|
||||
}]);
|
||||
let inner = QueueInterviewer::new(answers);
|
||||
|
|
|
|||
|
|
@ -438,9 +438,9 @@ paths:
|
|||
|
||||
/runs/{id}/compare:
|
||||
get:
|
||||
operationId: retrieveRunDiff
|
||||
operationId: retrieveRunCompare
|
||||
tags: [Run Outputs]
|
||||
summary: List Run Compare
|
||||
summary: Retrieve Run Compare
|
||||
description: Returns file-level diffs produced by the run, optionally filtered to a specific checkpoint.
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/RunId"
|
||||
|
|
@ -550,6 +550,12 @@ paths:
|
|||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ErrorResponse"
|
||||
"409":
|
||||
description: Run is not in a steerable state
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ErrorResponse"
|
||||
|
||||
/runs/{id}/preview:
|
||||
post:
|
||||
|
|
@ -578,6 +584,12 @@ paths:
|
|||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ErrorResponse"
|
||||
"409":
|
||||
description: Run has no active sandbox
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ErrorResponse"
|
||||
|
||||
# ── Workflows ─────────────────────────────────────────────────────────
|
||||
|
||||
|
|
@ -1174,10 +1186,9 @@ components:
|
|||
name: checkpoint
|
||||
in: query
|
||||
required: false
|
||||
description: Filter file diffs to a specific checkpoint. Defaults to all changes.
|
||||
description: Filter to a specific checkpoint ID. Omit to include all changes.
|
||||
schema:
|
||||
type: string
|
||||
default: "all"
|
||||
example: cp-3
|
||||
|
||||
PageLimit:
|
||||
|
|
@ -1506,7 +1517,9 @@ components:
|
|||
- confirmation
|
||||
|
||||
SubmitAnswerRequest:
|
||||
description: Request body for submitting an answer to a pending question.
|
||||
description: >
|
||||
Request body for submitting an answer to a pending question.
|
||||
At least one of `value`, `selected_option_key`, or `selected_option_keys` must be provided.
|
||||
type: object
|
||||
properties:
|
||||
value:
|
||||
|
|
@ -1515,8 +1528,14 @@ components:
|
|||
example: "Yes, proceed with the changes."
|
||||
selected_option_key:
|
||||
type: string
|
||||
description: Key of the selected option (for multiple-choice questions).
|
||||
description: Key of the selected option (for single-select multiple-choice questions).
|
||||
example: option_a
|
||||
selected_option_keys:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
description: Keys of selected options (for multi-select questions).
|
||||
example: ["option_a", "option_b"]
|
||||
|
||||
ErrorResponseEntry:
|
||||
description: A single error entry in an error response.
|
||||
|
|
@ -1676,6 +1695,8 @@ components:
|
|||
CodeLocation:
|
||||
description: A file and line location in the codebase.
|
||||
type: object
|
||||
required:
|
||||
- file
|
||||
properties:
|
||||
file:
|
||||
type: string
|
||||
|
|
@ -2228,7 +2249,10 @@ components:
|
|||
# ── Verification Schemas ─────────────────────────────────────────────
|
||||
|
||||
VerificationResult:
|
||||
description: Outcome of a verification control evaluation.
|
||||
description: >
|
||||
Outcome of a verification control evaluation.
|
||||
`skip`: evaluation was intentionally skipped (e.g., control is disabled).
|
||||
`na`: control does not apply to this run (e.g., Python lint on a Rust-only change).
|
||||
type: string
|
||||
enum:
|
||||
- pass
|
||||
|
|
@ -2250,13 +2274,19 @@ components:
|
|||
type: object
|
||||
required:
|
||||
- name
|
||||
- slug
|
||||
- description
|
||||
- type
|
||||
- status
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
description: Human-readable control name.
|
||||
example: Motivation
|
||||
slug:
|
||||
type: string
|
||||
description: URL-safe slug for linking to verification detail page.
|
||||
example: motivation
|
||||
description:
|
||||
type: string
|
||||
description: Short description of what the control verifies.
|
||||
|
|
@ -2318,6 +2348,8 @@ components:
|
|||
expires_in_secs:
|
||||
type: integer
|
||||
description: Time-to-live for the preview URL in seconds.
|
||||
minimum: 1
|
||||
maximum: 86400
|
||||
example: 3600
|
||||
|
||||
PreviewUrlResponse:
|
||||
|
|
@ -2409,6 +2441,7 @@ components:
|
|||
- name
|
||||
- slug
|
||||
- description
|
||||
- type
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
|
|
|
|||
|
|
@ -87,15 +87,15 @@ export const RunOutputsApiAxiosParamCreator = function (configuration?: Configur
|
|||
},
|
||||
/**
|
||||
* Returns file-level diffs produced by the run, optionally filtered to a specific checkpoint.
|
||||
* @summary List Run Compare
|
||||
* @summary Retrieve Run Compare
|
||||
* @param {string} id Unique run identifier (ULID).
|
||||
* @param {string} [checkpoint] Filter file diffs to a specific checkpoint. Defaults to all changes.
|
||||
* @param {string} [checkpoint] Filter to a specific checkpoint ID. Omit to include all changes.
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
retrieveRunDiff: async (id: string, checkpoint?: string, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||
retrieveRunCompare: async (id: string, checkpoint?: string, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||
// verify required parameter 'id' is not null or undefined
|
||||
assertParamExists('retrieveRunDiff', 'id', id)
|
||||
assertParamExists('retrieveRunCompare', 'id', id)
|
||||
const localVarPath = `/runs/{id}/compare`
|
||||
.replace(`{${"id"}}`, encodeURIComponent(String(id)));
|
||||
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
||||
|
|
@ -198,16 +198,16 @@ export const RunOutputsApiFp = function(configuration?: Configuration) {
|
|||
},
|
||||
/**
|
||||
* Returns file-level diffs produced by the run, optionally filtered to a specific checkpoint.
|
||||
* @summary List Run Compare
|
||||
* @summary Retrieve Run Compare
|
||||
* @param {string} id Unique run identifier (ULID).
|
||||
* @param {string} [checkpoint] Filter file diffs to a specific checkpoint. Defaults to all changes.
|
||||
* @param {string} [checkpoint] Filter to a specific checkpoint ID. Omit to include all changes.
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
async retrieveRunDiff(id: string, checkpoint?: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<RunCompare>> {
|
||||
const localVarAxiosArgs = await localVarAxiosParamCreator.retrieveRunDiff(id, checkpoint, options);
|
||||
async retrieveRunCompare(id: string, checkpoint?: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<RunCompare>> {
|
||||
const localVarAxiosArgs = await localVarAxiosParamCreator.retrieveRunCompare(id, checkpoint, options);
|
||||
const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
|
||||
const localVarOperationServerBasePath = operationServerMap['RunOutputsApi.retrieveRunDiff']?.[localVarOperationServerIndex]?.url;
|
||||
const localVarOperationServerBasePath = operationServerMap['RunOutputsApi.retrieveRunCompare']?.[localVarOperationServerIndex]?.url;
|
||||
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
|
||||
},
|
||||
/**
|
||||
|
|
@ -246,14 +246,14 @@ export const RunOutputsApiFactory = function (configuration?: Configuration, bas
|
|||
},
|
||||
/**
|
||||
* Returns file-level diffs produced by the run, optionally filtered to a specific checkpoint.
|
||||
* @summary List Run Compare
|
||||
* @summary Retrieve Run Compare
|
||||
* @param {string} id Unique run identifier (ULID).
|
||||
* @param {string} [checkpoint] Filter file diffs to a specific checkpoint. Defaults to all changes.
|
||||
* @param {string} [checkpoint] Filter to a specific checkpoint ID. Omit to include all changes.
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
retrieveRunDiff(id: string, checkpoint?: string, options?: RawAxiosRequestConfig): AxiosPromise<RunCompare> {
|
||||
return localVarFp.retrieveRunDiff(id, checkpoint, options).then((request) => request(axios, basePath));
|
||||
retrieveRunCompare(id: string, checkpoint?: string, options?: RawAxiosRequestConfig): AxiosPromise<RunCompare> {
|
||||
return localVarFp.retrieveRunCompare(id, checkpoint, options).then((request) => request(axios, basePath));
|
||||
},
|
||||
/**
|
||||
* Returns token and cost usage broken down by stage and model for a specific run.
|
||||
|
|
@ -287,14 +287,14 @@ export class RunOutputsApi extends BaseAPI {
|
|||
|
||||
/**
|
||||
* Returns file-level diffs produced by the run, optionally filtered to a specific checkpoint.
|
||||
* @summary List Run Compare
|
||||
* @summary Retrieve Run Compare
|
||||
* @param {string} id Unique run identifier (ULID).
|
||||
* @param {string} [checkpoint] Filter file diffs to a specific checkpoint. Defaults to all changes.
|
||||
* @param {string} [checkpoint] Filter to a specific checkpoint ID. Omit to include all changes.
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
public retrieveRunDiff(id: string, checkpoint?: string, options?: RawAxiosRequestConfig) {
|
||||
return RunOutputsApiFp(this.configuration).retrieveRunDiff(id, checkpoint, options).then((request) => request(this.axios, this.basePath));
|
||||
public retrieveRunCompare(id: string, checkpoint?: string, options?: RawAxiosRequestConfig) {
|
||||
return RunOutputsApiFp(this.configuration).retrieveRunCompare(id, checkpoint, options).then((request) => request(this.axios, this.basePath));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ export interface CodeLocation {
|
|||
/**
|
||||
* File path.
|
||||
*/
|
||||
'file'?: string;
|
||||
'file': string;
|
||||
/**
|
||||
* Line number in the file.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -28,11 +28,15 @@ export interface RunVerificationControl {
|
|||
* Human-readable control name.
|
||||
*/
|
||||
'name': string;
|
||||
/**
|
||||
* URL-safe slug for linking to verification detail page.
|
||||
*/
|
||||
'slug': string;
|
||||
/**
|
||||
* Short description of what the control verifies.
|
||||
*/
|
||||
'description': string;
|
||||
'type'?: VerificationType;
|
||||
'type': VerificationType;
|
||||
'status': VerificationResult;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
|
||||
/**
|
||||
* Request body for submitting an answer to a pending question.
|
||||
* Request body for submitting an answer to a pending question. At least one of `value`, `selected_option_key`, or `selected_option_keys` must be provided.
|
||||
*/
|
||||
export interface SubmitAnswerRequest {
|
||||
/**
|
||||
|
|
@ -23,8 +23,12 @@ export interface SubmitAnswerRequest {
|
|||
*/
|
||||
'value'?: string;
|
||||
/**
|
||||
* Key of the selected option (for multiple-choice questions).
|
||||
* Key of the selected option (for single-select multiple-choice questions).
|
||||
*/
|
||||
'selected_option_key'?: string;
|
||||
/**
|
||||
* Keys of selected options (for multi-select questions).
|
||||
*/
|
||||
'selected_option_keys'?: Array<string>;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ export interface VerificationControl {
|
|||
* Short description of what the control verifies.
|
||||
*/
|
||||
'description': string;
|
||||
'type'?: VerificationType;
|
||||
'type': VerificationType;
|
||||
'mode'?: VerificationMode;
|
||||
/**
|
||||
* F1 score of the control\'s AI evaluator.
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
|
||||
/**
|
||||
* Outcome of a verification control evaluation.
|
||||
* Outcome of a verification control evaluation. `skip`: evaluation was intentionally skipped (e.g., control is disabled). `na`: control does not apply to this run (e.g., Python lint on a Rust-only change).
|
||||
*/
|
||||
|
||||
export const VerificationResult = {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue