Skip to content
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
61909e8
feat(contract): require structured review results (#119)
CompleteDotTech Jul 6, 2026
fdc255f
feat(contract): record supporting review files (#119)
CompleteDotTech Jul 6, 2026
44d2663
chore(hosted): track CompleteTech dogfood adapter (#119)
CompleteDotTech Jul 6, 2026
3cd400a
feat(hosted): add bounded review fix loop (#119)
CompleteDotTech Jul 6, 2026
669fca6
fix(hosted): address review gating and evidence gaps (#119)
CompleteDotTech Jul 6, 2026
a6a794d
fix(hosted): apply review hardening (#119)
CompleteDotTech Jul 6, 2026
7cfc1be
fix(hosted): align review context and routing contract (#119)
CompleteDotTech Jul 6, 2026
4e19b93
fix(hosted): enforce result contract before review loops (#119)
CompleteDotTech Jul 6, 2026
9091dc6
fix(hosted): tighten review result validation (#119)
CompleteDotTech Jul 6, 2026
cacece4
fix(worker): enforce v2 review contract invariants (#119)
CompleteDotTech Jul 6, 2026
6bdfb7b
fix(contract): validate result exit reasons (#119)
CompleteDotTech Jul 6, 2026
2cc54f7
fix(contract): close result envelope validation (#119)
CompleteDotTech Jul 6, 2026
cec7a28
fix(contract): align session brief validation (#119)
CompleteDotTech Jul 6, 2026
e5b59c8
fix(hosted): harden review routing evidence (#119)
CompleteDotTech Jul 6, 2026
00c3793
ci: run hosted adapter python tests (#119)
CompleteDotTech Jul 6, 2026
2584b34
fix(hosted): reject team-style bot mentions (#119)
CompleteDotTech Jul 6, 2026
2617a2c
Merge branch 'main' into codex/review-fix-loop
BunsDev Jul 6, 2026
bf9c035
Potential fix for pull request finding
BunsDev Jul 6, 2026
089d347
fix(worker): align v2 review result contract
CompleteDotTech Jul 6, 2026
5d22cce
fix(adapter): handle missing webhook secret
CompleteDotTech Jul 6, 2026
d03b5a2
Merge remote-tracking branch 'origin/main' into codex/review-fix-loop
CompleteDotTech Jul 6, 2026
73bb736
Merge branch 'main' into codex/review-fix-loop
BunsDev Jul 6, 2026
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@ keys/
*.pem
.env
.DS_Store
deploy/coven-github/.coven-github-private-key.pem
deploy/coven-github/coven-github-policy.json
deploy/coven-github/coven-github-state/
95 changes: 88 additions & 7 deletions crates/github/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,8 @@ pub const DEFAULT_API_BASE_URL: &str = "https://api.github.com";

/// Major version of the coven-code headless execution contract this adapter
/// speaks. See `docs/headless-contract.md`. Bump only on breaking changes.
pub const HEADLESS_CONTRACT_VERSION: &str = "1";
pub const HEADLESS_CONTRACT_VERSION: &str = "2";

fn default_contract_version() -> String {
HEADLESS_CONTRACT_VERSION.to_string()
}
const GITHUB_API_VERSION: &str = "2026-03-10";

#[derive(Debug, Clone, PartialEq, Eq)]
Expand Down Expand Up @@ -175,18 +172,18 @@ pub enum TaskKind {

/// Structured result envelope written by coven-code --headless.
#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct SessionResult {
/// Contract major version. Defaults to the current version when a runtime
/// omits it, but conformant producers MUST emit it. See
/// Contract major version. Conformant producers MUST emit it. See
/// `docs/headless-contract.md`.
#[serde(default = "default_contract_version")]
pub contract_version: String,
pub status: SessionStatus,
pub branch: Option<String>,
pub commits: Vec<CommitInfo>,
pub files_changed: Vec<String>,
pub summary: String,
pub pr_body: String,
pub review: ReviewResult,
Comment thread
CompleteDotTech marked this conversation as resolved.
pub exit_reason: Option<ExitReason>,
}

Expand All @@ -200,11 +197,95 @@ pub enum SessionStatus {
}

#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct CommitInfo {
pub sha: String,
pub message: String,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct ReviewResult {
pub mode: ReviewMode,
pub evidence_status: ReviewEvidenceStatus,
pub reviewed_files: Vec<String>,
pub supporting_files: Vec<String>,
pub findings: Vec<ReviewFinding>,
pub tests_run: Vec<ReviewTestRun>,
pub no_findings_reason: Option<String>,
pub limitations: Vec<String>,
}

impl ReviewResult {
pub fn none() -> Self {
Self {
mode: ReviewMode::None,
evidence_status: ReviewEvidenceStatus::NotApplicable,
reviewed_files: Vec::new(),
supporting_files: Vec::new(),
findings: Vec::new(),
tests_run: Vec::new(),
no_findings_reason: None,
limitations: Vec::new(),
}
}
}

#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum ReviewMode {
None,
PullRequest,
ReviewComment,
}

#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum ReviewEvidenceStatus {
NotApplicable,
Complete,
Partial,
Missing,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct ReviewFinding {
pub severity: ReviewSeverity,
pub file: String,
pub line: Option<u64>,
pub title: String,
pub body: String,
pub recommendation: Option<String>,
}

#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum ReviewSeverity {
Info,
Low,
Medium,
High,
Critical,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct ReviewTestRun {
pub command: String,
pub status: ReviewTestStatus,
pub output_summary: Option<String>,
}

#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum ReviewTestStatus {
Passed,
Failed,
NotRun,
Unknown,
}

#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum ExitReason {
Expand Down
1 change: 1 addition & 0 deletions crates/github/src/tasks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ mod tests {
files_changed: vec![],
summary: "Done".to_string(),
pr_body: "Body".to_string(),
review: crate::ReviewResult::none(),
exit_reason: None,
},
Some(9),
Expand Down
28 changes: 24 additions & 4 deletions crates/worker/src/brief.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,18 @@ use std::path::Path;
use coven_github_api::{Task, TaskKind, HEADLESS_CONTRACT_VERSION};
use coven_github_config::FamiliarConfig;

fn default_contract_version() -> String {
HEADLESS_CONTRACT_VERSION.to_string()
fn deserialize_contract_version<'de, D>(deserializer: D) -> Result<String, D::Error>
where
D: serde::Deserializer<'de>,
{
let version = String::deserialize(deserializer)?;
if version != HEADLESS_CONTRACT_VERSION {
return Err(serde::de::Error::custom(format!(
"unsupported session brief contract_version {}; expected {}",
version, HEADLESS_CONTRACT_VERSION
)));
}
Ok(version)
}

/// The session-brief.json schema injected into coven-code --headless.
Expand All @@ -17,19 +27,25 @@ fn default_contract_version() -> String {
/// write authority (comments, Check Runs, branches, PRs) stays with the adapter
/// behind its publication gate. See issue #4.
#[derive(Debug, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct SessionBrief {
/// Contract major version this brief is written against. See
/// `docs/headless-contract.md`.
#[serde(default = "default_contract_version")]
#[serde(deserialize_with = "deserialize_contract_version")]
pub contract_version: String,
pub trigger: String,
pub repo: RepoBrief,
pub task: TaskBrief,
pub familiar: FamiliarBrief,
pub workspace: WorkspaceBrief,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub review_context: Option<serde_json::Value>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub audit_instruction: Option<String>,
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct RepoBrief {
pub owner: String,
pub name: String,
Expand All @@ -38,7 +54,7 @@ pub struct RepoBrief {
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "snake_case")]
#[serde(tag = "kind", rename_all = "snake_case", deny_unknown_fields)]
pub enum TaskBrief {
FixIssue {
issue_number: u64,
Expand All @@ -57,6 +73,7 @@ pub enum TaskBrief {
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct FamiliarBrief {
pub id: String,
pub display_name: String,
Expand All @@ -65,6 +82,7 @@ pub struct FamiliarBrief {
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct WorkspaceBrief {
pub root: String,
}
Expand Down Expand Up @@ -136,6 +154,8 @@ pub fn build(
workspace: WorkspaceBrief {
root: workspace.to_string_lossy().to_string(),
},
review_context: None,
audit_instruction: None,
}
}

Expand Down
Loading
Loading