Skip to content
Closed
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)
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
cf4c313
Initial plan
Copilot Jul 6, 2026
29926e1
fix webhook config handling
Copilot Jul 6, 2026
8ef2815
Merge remote task branch
Copilot Jul 6, 2026
68d70a2
fix review thread feedback
Copilot 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
8 changes: 7 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,20 @@ env:

jobs:
check:
name: cargo check + clippy + test
name: python + cargo check + clippy + test
runs-on: ubuntu-latest
permissions:
contents: read
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,
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