Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
61909e8
feat(contract): require structured review results (#119)
romgenie Jul 6, 2026
fdc255f
feat(contract): record supporting review files (#119)
romgenie Jul 6, 2026
44d2663
chore(hosted): track CompleteTech dogfood adapter (#119)
romgenie Jul 6, 2026
3cd400a
feat(hosted): add bounded review fix loop (#119)
romgenie Jul 6, 2026
669fca6
fix(hosted): address review gating and evidence gaps (#119)
romgenie Jul 6, 2026
a6a794d
fix(hosted): apply review hardening (#119)
romgenie Jul 6, 2026
7cfc1be
fix(hosted): align review context and routing contract (#119)
romgenie Jul 6, 2026
4e19b93
fix(hosted): enforce result contract before review loops (#119)
romgenie Jul 6, 2026
9091dc6
fix(hosted): tighten review result validation (#119)
romgenie Jul 6, 2026
cacece4
fix(worker): enforce v2 review contract invariants (#119)
romgenie Jul 6, 2026
6bdfb7b
fix(contract): validate result exit reasons (#119)
romgenie Jul 6, 2026
2cc54f7
fix(contract): close result envelope validation (#119)
romgenie Jul 6, 2026
cec7a28
fix(contract): align session brief validation (#119)
romgenie Jul 6, 2026
e5b59c8
fix(hosted): harden review routing evidence (#119)
romgenie Jul 6, 2026
00c3793
ci: run hosted adapter python tests (#119)
romgenie Jul 6, 2026
2584b34
fix(hosted): reject team-style bot mentions (#119)
romgenie 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
romgenie Jul 6, 2026
5d22cce
fix(adapter): handle missing webhook secret
romgenie Jul 6, 2026
d03b5a2
Merge remote-tracking branch 'origin/main' into codex/review-fix-loop
romgenie 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
6 changes: 5 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,18 @@ env:

jobs:
check:
name: cargo check + clippy + test
name: python + cargo check + clippy + test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
components: clippy
- uses: Swatinem/rust-cache@v2
- name: hosted adapter python compile
run: python -B -m py_compile deploy/coven-github/coven_github_adapter.py deploy/coven-github/test_coven_github_adapter.py
- name: hosted adapter python tests
run: python -B -m unittest discover -s deploy/coven-github -p "test_*.py"
- name: cargo check
run: cargo check --all-targets
- name: clippy
Expand Down
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,7 @@ keys/
*.pem
.env
.DS_Store
.comux*
deploy/coven-github/.coven-github-private-key.pem
deploy/coven-github/coven-github-policy.json
deploy/coven-github/coven-github-state/
.comux*
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
romgenie 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